Reputation: 1519
I need to post a image to Twitter. I have integrated Twitter in my app. I need to tweet the image as such not as an URL link. I don't want to use TwitPic.
I used the following code to create the multipart entity. It give 404 error.
Bitmap bm = null;
String encodedImage = "";
try {
URL aURL = new URL("http://50.57.227.117/blacksheep/uploaded/Detailed_images/961314275649aladdins.jpg");
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, 8192);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
imageBytes = baos.toByteArray();
encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
Log.v("encodedImage >>",encodedImage);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"https://api.twitter.com/1.1/statuses/update_with_media.json");
ByteArrayBody bab = new ByteArrayBody(imageBytes, "forest.jpg");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("media", bab);
reqEntity.addPart("status", new StringBody("test image"));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
BufferedReader reader = new BufferedReader(new InputStreamReader(
response.getEntity().getContent(), "UTF-8"));
String sResponse;
StringBuilder s = new StringBuilder();
while ((sResponse = reader.readLine()) != null) {
s = s.append(sResponse);
}
System.out.println("Response: " + s);
// Update status
//twitter4j.Status response = twitter.updateStatus(encodedImage);
// twitter4j.Status response1 = twitter.updateStatus(status);
//Log.d("Status", "> " + response1.getText());
} catch (TwitterException e) {
// Error in updating status
Log.d("Twitter Update Error", e.getMessage());
}
Upvotes: 2
Views: 3516
Reputation: 64026
Using 4.0.3 (perhaps earlier) it's very simple to embed images in a tweet with twitter4j:
Twitter twtobj;
StatusUpdate stsupd;
Status stsres;
twtobj=twitterFactory.getInstance();
twtobj.setOAuthConsumer(csmkey,csmsec);
twtobj.setOAuthAccessToken(new AccessToken(acstkn,acssec));
stsupd=new StatusUpdate(msgtxt);
if(medurls.length>0) {
long[] medidns=new long[medurls.length];
for(int xa=0; xa<medurls.length; xa++) {
String medurl=Util.resolveRelativeUrl(medurls[xa]);
InputStream imgstm=null;
try {
imgstm=new URL(medurl).openConnection().getInputStream();
medidns[xa]=twtobj.uploadMedia(medurl,imgstm).getMediaId(); // this actually uploads the image to Twitter at this point
}
catch(MalformedURLException thr) { throw new ShfFail(Fail.IMAGE_URL ,"The media URL is not valid: " +medurl+" ("+thr.getMessage()+")"); }
catch(IOException thr) { throw new ShfFail(Fail.IMAGE_READ,"The media could not be read: "+medurl+" ("+thr.getMessage()+")"); }
finally { GenUtil.close(imgstm); }
}
stsupd.setMediaIds(medidns);
}
stsres=twtobj.updateStatus(stsupd);
Note that up to 4 images, or 1 animated GIF, or 1 video are allowed, as of 2015-06-10.
Note also that I am capturlng the image streams to close them explicitly in the outer block (not shown). This may be unnecessary, but I can't find positive confirmation of that.
If anyone cares, resolveRelativeUrls
is a convenience to allow a relative path to be resolved as a file URL from the current folder:
static public String resolveRelativeUrl(String url) {
if(!TextUtil.stringCT(url,"://")) {
url=new File(url).getAbsoluteFile().toURI().toString();
}
return url;
}
The utility method stringCT
is case-insensitive contains.
Upvotes: 2
Reputation: 1793
First attempt:
So it seemed like you were using Apache's old http client to make a request external to the library you were using to help integrate with twitter, twitter4j. I assumed you were using a version prior to 3.03 which is latest, and didn't want you to upgrade. You see, update_with_media is quite new, so I didn't think your version had implemented it.
The problem with what you were doing is that twitter uses oauth for authentication. So you'd need to "sign" a request with the access token you'd obtained. Twitter4j, AFAIK, does this for you. You can't use a seperate client to make some calls without reference to your nice helper library without breaking authentication.
The endpoint, ../update_with_media
is defined to update a status for the currently authenticating user. I suspect that, since there was no access token and no user in your request, that endpoint doesn't even make sense, so twitter were interpreting it as a 404
(not found) rather than a 401
(unauthorized)- funny.
So the first attempt was not to require you to upgrade to twitter4j. It's a pain to upgrade sometimes! Instead, you can hack with the library as is detailed with this blog. But that wasn't easy as the libraries were different.
So, something else we could try, if you really wanted to make a seperate request to twitter4j, was to actually do the signing, perhaps using scribe to make it easier.... roughly:
final OAuthService myTwitterService = TwitterClient.getTwitterClient().getService();
final OAuthRequest aNiceOAuthRequest = new org.scribe.model.OAuthRequest(
YOURPOST, THATURL);
etc.
Second attempt:
But let's not do all this- turns out you had the latest version of twitter4j anyway. Sorry for going down a cul-de-sac first- I shouldn't have assumed, but I've included the above for help for anybody else should they need it.
It turns out the latest version has implemented this endpoint- documentation here. Except it takes a StatusUpdate
object instead. So you want to do something like:
final StatusUpdate statusUpdate = new StatusUpdate("Hallee hallo my status java.lang.String here...");
// now do as you did until:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
imageBytes = baos.toByteArray();
encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
// then flip the stream
byte[] myTwitterUploadBytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(myTwitterUploadBytes);
// doo and double check your encoding etc, similar to in your question..
statusUpdate.setMedia("give me a java.lang.String name", bis);
// then continue just using twitter for j- update status as you would
//... get twitter etc...
//
twitter4j.Status response = twitter.updateStatus(statusUpdate);
Haven't currently got a box on me to test- should be about right. If it still gives 404s, what is the error code in the response? Are you authenticated?
If that doesn't work, we can try some of the above too as a back up.
Hope this helps,
best,
Tom.
Upvotes: 5