http://eggie5.com/8-hook-share-picture-via-menu-android

You know in the android gallery when you view a picture there is the share menu that allows you to upload your picture to various services. It is the job of the app to handle the upload - for example on my phone (depending on the apps you have installed) facebook, picasa, blogger all have entries in that list. This article will describe the process to get your app in that list and post the picture over HTTP.

Basically there are 3 steps to get this working:

  1. Register your app w/ the android platform to show your app in the platform share menu. (see Intents)
  2. Get the image from the Album app using android APIs (see ContentResolver)
  3. Do actual HTTP post request

1. Add hook to AndroidManifest.xml

If you intend to get your app in the share menu you must register that intent (pun intended) w/ the andoid system. This is done via and intent-filter in the AndroidManifest.xml file. 

In order to use the internet to make and HTTP request we must also register that w/ Android via the use-permission directive in the manifest file. See below example:

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                            


 

2. Get image from Gallery

Getting an image from the camera isn't as straight forward as it seems. It's not just open the file at this path - you must use the ContentResolver/ContentProvider API in android - which the gallery app exposes. See code example:

public void onCreate(Bundle savedInstanceState){    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    Intent intent = getIntent();    Bundle extras = intent.getExtras();    String action = intent.getAction();    // if this is from the share menu    if (Intent.ACTION_SEND.equals(action))    {        if (extras.containsKey(Intent.EXTRA_STREAM))        {            try            {                // Get resource path from intent callee                Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);                // Query gallery for camera picture via                // Android ContentResolver interface                ContentResolver cr = getContentResolver();                InputStream is = cr.openInputStream(uri);                // Get binary bytes for encode                byte[] data = getBytesFromFile(is);                // base 64 encode for text transmission (HTTP)                byte[] encoded_data = Base64.encodeBase64(data);                String data_string = new String(encoded_data); // convert to string                SendRequest(data_string);                return;            } catch (Exception e)            {                Log.e(this.getClass().getName(), e.toString());            }        } else if (extras.containsKey(Intent.EXTRA_TEXT))        {            return;        }    }}


 

First we get a path to the image (uri) from the share menu of the gallery when we clicked on share. It's not however just a path to the image - it's a content uri which is android platform specific way to refrence a resource. It looks somehting like this content://com.example.gallery/3. With a URI you can then query gallery for the resource. The key here is getContentResolver() method - it will get you a handle to android internal DRM system which the cameria/gallery exposes(uses). Then in order to sent the image over HTTP we must convert it to plaintext encoding (base64) from binary. We do this by gettings it's bits and converting to base64 string representation (details are beyond the scope of this article - see source for details).

3. HTTP Post Request

Rather than choose a high level library for the HTTP action I chose to implement it using sockets as an exercise (more fun - we can really see what's happening).

First we build the xml post body string. We then create the request and send it. Note: most people would do this using multipart/mime but I choose just to encode the image into the xml photo node.

private void SendRequest(String data_string){    try    {        String xmldata = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"                + "" + data_string                + "via android - " + new Date().toString()                + "";        // Create socket        String hostname = "eggie5.com";        String path = "/photos";        int port = 80;        InetAddress addr = InetAddress.getByName(hostname);        Socket sock = new Socket(addr, port);        // Send header        BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(                sock.getOutputStream(), "UTF-8"));        wr.write("POST " + path + " HTTP/1.1\r\n");        wr.write("Host: eggie5.com\r\n");        wr.write("Content-Length: " + xmldata.length() + "\r\n");        wr.write("Content-Type: text/xml; charset=\"utf-8\"\r\n");        wr.write("Accept: text/xml\r\n");        wr.write("\r\n");        // Send data        wr.write(xmldata);        wr.flush();        // Response        BufferedReader rd = new BufferedReader(new InputStreamReader(                sock.getInputStream()));        String line;        while ((line = rd.readLine()) != null)        {            Log.v(this.getClass().getName(), line);        }    } catch (Exception e)    {        Log.e(this.getClass().getName(), "Upload failed", e);    }}


 

Then on the server side - I must decode the base64 stream back into binary which I did in ruby:

Base64.decode64(incoming_file)

See full source on github: https://github.com/eggie5/android-share-menu

Next Steps:

When the image is uploading the UI kinda locks up - the next step would be to have some type of progress bar like the facebook or picasa app does.

Also usually the images are way to big for the front page of this site (where they go) - should implement some type of resize on the phone. This would also make the upload faster.

 

 

ps

Uros Mesaric 3 comments collapsed Collapse Expand

Tnx for code. Just what I needed.

  • A Like
  • Reply
  • 8 months ago
  • 2 Likes

eggie5 2 comments collapsed Collapse Expand

glad i could help!

  • A Like
  • Reply
  • 7 months ago
  • in reply to Uros Mesaric
  • 0 Like

Rakesh Raut739 1 comment collapsed Collapse Expand

thanxxxxxx alot exactly the same thing i want.....

  • A Like
  • Reply
  • 3 months ago
  • in reply to eggie5
  • 0 Like

Stephen Sykes 1 comment collapsed Collapse Expand

Added thread via AsyncTask for server call and progress dialog. Updated code available at my github fork:
https://github.com/sasykes/and...

  • A Like
  • Reply
  • 9 months ago
  • 1 Like

Dia_mor 2 comments collapsed Collapse Expand

finally code that works sending data to a server!!! thanks!! ibe been trying tens of examples and this is the first one successfull!!

  • A Like
  • Reply
  • 10 months ago
  • 1 Like

eggie5 1 comment collapsed Collapse Expand

GOOD

  • A Like
  • Reply
  • 10 months ago
  • in reply to Dia_mor
  • 0 Like

Michealkl 1 comment collapsed Collapse Expand

Thanks for the code. How if I want to resize the photo to any size(VGA, 1M...) on the phone before upload to server?

  • A Like
  • Reply
  • 5 days ago
  • 0 Like

Praveentubachi 2 comments collapsed Collapse Expand

Hi all,
I found this link useful and yes,
thanks for this good example. In this example we get the URI
which gives the path for the resource in the gallery, that URI isn't the
path pointing towards the location of the resource(Image) in sdcard(If
it wer to have existed in sdcard). I would like to know how you the path
which gives the location for the resource. Please Help. Thanks in
advance.

  • A Like
  • Reply
  • 3 months ago
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

Well the Gallery app "owns" the images and is implemented in such a way that you must use the ContentResolver API to get access to them. I suppose, of course, that there is a file path to them somewhere on the SD card, but those details aren't exposed.

  • A Like
  • Reply
  • 3 months ago
  • in reply to Praveentubachi
  • 0 Like

Ashley McConnell 5 comments collapsed Collapse Expand

Slightly off topic, but do you happen to know if you can start the "Share Via" activity from your own activity?

  • A Like
  • Reply
  • 8 months ago
  • 0 Like

eggie5 4 comments collapsed Collapse Expand

uh, not sure what you mean...

  • A Like
  • Reply
  • 8 months ago
  • in reply to Ashley McConnell
  • 0 Like

Ashley McConnell 3 comments collapsed Collapse Expand

Hi Eggie5,  

After an hour searching I found the answer here: - http://stackoverflow.com/quest... (2 mins after posting above :))I mean I would like to take a screenshot of my app, save it to the SD card then call the Share Via dialog (like you get when you take a pic on the camera and it allows you to send it to email / tweet / facebook etc.)Hope this helps,All the best,Ash

  • A Like
  • Reply
  • 8 months ago
  • in reply to eggie5
  • 0 Like

eggie5 2 comments collapsed Collapse Expand

Are you programaticly want to invoke the share via dialog from your activity? How do you take a screenshot? I'm curious...

  • A Like
  • Reply
  • 8 months ago
  • in reply to Ashley McConnell
  • 0 Like

Ashley McConnell 1 comment collapsed Collapse Expand

I suspect it's only possible to take a screenshot with an OpenGL app, but this is how: - http://stackoverflow.com/quest... HTH!

  • A Like
  • Reply
  • 8 months ago
  • in reply to eggie5
  • 0 Like

Joevolcano 5 comments collapsed Collapse Expand

I used this code and I still cant get my app to show up inthe share menu on the emulator or the droid x after selecting some image ans clicking on share... it just goes right to an mms message... frustrating....

  • A Like
  • Reply
  • 8 months ago
  • 0 Like

Joevolcano 4 comments collapsed Collapse Expand

I think it is working for sharing 1 image but not multi

  • A Like
  • Reply
  • 8 months ago
  • in reply to Joevolcano
  • 0 Like

eggie5 3 comments collapsed Collapse Expand

I designed it to only upload 1 photo at a time. 

To upload multiple you might have to change something in the manifest file. If you figure it out, let me know.

  • A Like
  • Reply
  • 8 months ago
  • in reply to Joevolcano
  • 0 Like

Joevolcano 2 comments collapsed Collapse Expand

The following settings I have in my AndroidManifest.xml will handle single and multiple share in the emulator.
      
  










      

This my oncreate method to access the multiple files. it just logs the uri

    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                Intent intent = getIntent();            Bundle extras = intent.getExtras();            String action = intent.getAction();            // if this is from the share menu            if (Intent.ACTION_SEND_MULTIPLE.equals(action))            {                   if (extras.containsKey(Intent.EXTRA_STREAM))                 {                                       ArrayList theFileList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);                     try                     {                         for(Uri uri: theFileList)         {         Log.i("INFO", uri.getPath());                 }         return;                     }          catch (Exception e)                     {                         Log.e(this.getClass().getName(), e.toString());         }             }         }    }

  • A Like
  • Reply
  • 8 months ago
  • in reply to eggie5
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

cool thanks for the update - maybe I should add it to the code I posted...

  • A Like
  • Reply
  • 8 months ago
  • in reply to Joevolcano
  • 1 Like

Anzar Zulfiqar 2 comments collapsed Collapse Expand

cant we give the priority to ur intent filter in this case, so that when the menu is displayed by the android system, our application should be the first option

  • A Like
  • Reply
  • 8 months ago
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

It just seems alphabetical on my phone.... I don't know any android settings to change the order...

  • A Like
  • Reply
  • 8 months ago
  • in reply to Anzar Zulfiqar
  • 0 Like

Dia_mor 2 comments collapsed Collapse Expand

hi there. can you show the server side? is it php?

  • A Like
  • Reply
  • 10 months ago
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

Hi,
The server side can be anything - this particular site is running ruby. The server just needs to accept an xml post request with base64 encoded photo data in the tag. The server would then need to base64 decode it and save to disk.

Here is a snippet of my ruby server code:

#decode binary data
@temp_file = Base64.decode64(incoming_file)

#save to disk
#FileUtils.mkdir_p(full_directory_name)
#File.open(full_filename, "wb") {|f| f.write(@temp_file.read)}

#or save to amazon s3
@s3 = Rightscale::S3.new(ENV['AMAZON_ACCESS_KEY_ID'], ENV['AMAZON_SECRET_ACCESS_KEY'])
b=@s3.bucket("#{my_bucket}#{Rails.env}")
b.put("#{photo_path}/#{self.id}", @temp_file, {}, "public-read-write")

  • A Like
  • Reply
  • 10 months ago
  • in reply to Dia_mor
  • 0 Like

Melpo 2 comments collapsed Collapse Expand

Hm, eclipse is complaining about Base64, SendRequest and getBytesFromFile. Where can I import these from?

  • A Like
  • Reply
  • 1 year ago
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

if you look at my github example project the library is included, https://github.com/eggie5/andr... or just search org.apache.commons.codec.binary.Base64 and get the jar off the internet and include it in whatever build system/IDE you use.

  • A Like
  • Reply
  • 1 year ago
  • in reply to Melpo
  • 0 Like

Marius 2 comments collapsed Collapse Expand

This very example is something I've been looking for. Is it possible for somebody to make a ready-complied version for me? This would be very useful for calling from App Inventor apps.

marius@evang.no

  • A Like
  • Reply
  • 1 year ago
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

never used app inventor before... sorry...

  • A Like
  • Reply
  • 1 year ago
  • in reply to Marius
  • 0 Like

Erikswed104 3 comments collapsed Collapse Expand

Thanks for the code snipe
Oh my bad of course i messed up the xml.
and also i had to covert the uri to absolute path something.
Can i ask , when i press the post_to_eggie5 in the share menu , screen goes black with the text post_to_eggie5 at the top.
How do i disable that?

  • A Like
  • Reply
  • 1 year ago
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

updated - if your logcat is still broke sounds like an issue w/ your eclipse/android sdk setup...

  • A Like
  • Reply
  • 1 year ago
  • in reply to Erikswed104
  • 0 Like

eggie5 1 comment collapsed Collapse Expand

hi, actually I didn't finish this code yet - I got too busy w/ finals at school. I plan on finishing it this week - I'll let you know...

  • A Like
  • Reply
  • 1 year ago
  • in reply to Erikswed104
  • 0 Like

Erikswed104 1 comment collapsed Collapse Expand

hmm
Im new to Android and created a new android project in Eclipse
but get "unable to instantiate activity error from the Logcat log.

Do I have to put something in that addAttachment(Strin... method??
hmm

I did put an image into my virtual sdcard and try sharing clicking but program/activity crash

  • A Like
  • Reply
  • 1 year ago
  • 0 Like

 

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. 【DB笔试面试659】在Oracle中,SELECT ...
  2. 【DB笔试面试664】在Oracle中,模拟死锁产
  3. 【DB笔试面试677】在Oracle中,对于一个NUM
  4. 图像翻转
  5. Ansible 日常使用技巧 - 运维总结
  6. xml 和 json各自的优缺点
  7. 什么是 Three.js?
  8. JSON Schema 是什么?
  9. laravel
  10. jq的DOM操作与事件操作02的有感记录