从Android上传图像到tumblr API

时间:2012-12-12 17:22:56

标签: android api encoding tumblr

假设使用Tumblr API上传图片的人很容易。事实并非如此。 (编辑现在,请参阅此条目末尾的编辑2

我的应用应该将图片上传到tumblr。我更喜欢从服务中做到这一点,但是现在我使用的活动在完成上传后立即关闭。在OnCreate()中,用户已通过身份验证:

consumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);

// It uses this signature by default
// consumer.setMessageSigner(new HmacSha1MessageSigner());

provider = new CommonsHttpOAuthProvider(REQUEST_TOKEN_URL,ACCESS_TOKEN_URL,AUTH_URL);

String authUrl;
try 
{
authUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
Log.d(TAG, "Auth url:" + authUrl);

startActivity(new Intent("android.intent.action.VIEW", Uri.parse(authUrl)));

} 

这会打开一个浏览器活动,用户可以在其中添加用户名和密码,然后应用程序返回活动(这也是我必须使用活动的原因,我不知道如何从服务中执行此操作)< / p>

从浏览器返回提取数据:

Uri uri = context.getIntent().getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) 
{  
    Log.d(TAG, "uri!=null");
    String verifier = uri.getQueryParameter("oauth_verifier");  
    Log.d(TAG, "verifier"+verifier);
    try 
    {
        provider.setOAuth10a(true);
        provider.retrieveAccessToken(consumer, verifier);
        Log.d(TAG, "try");
    } 
    catch (Exception e) 
    {
        Log.e(TAG, e.toString());
        e.printStackTrace();
    } 
OAUTH_TOKEN = consumer.getToken();
OAUTH_SECRET = consumer.getTokenSecret();

这两个片段中的大部分都是from here,而且效果很好。

使用这些令牌,我现在可以尝试将数据放在tumblr上。当我尝试添加文本时,使用此方法可以正常工作:

private void createText()
{
    if(!OAUTH_TOKEN.equals(""))
    {

        HttpContext context = new BasicHttpContext();
        HttpPost request = new HttpPost("http://api.tumblr.com/v2/blog/" + blogname + ".tumblr.com/post");

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs.add(new BasicNameValuePair("type", "text")); 
        nameValuePairs.add(new BasicNameValuePair("body", "this is just a test"));  

        try 
        {
        request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        } 
        catch (UnsupportedEncodingException e1) 
        {
            Log.e(TAG, e1.toString());
            e1.printStackTrace();
        }

        if (consumer == null)
        {
            consumer = new CommonsHttpOAuthConsumer(OAuthConstants.TUMBR_CONSUMERKEY, OAuthConstants.TUMBR_SECRETKEY);
        }
        if (OAUTH_TOKEN == null || OAUTH_SECRET == null)
        {
            Log.e(TAG, "Not logged in error");
        }
        consumer.setTokenWithSecret(OAUTH_TOKEN, OAUTH_SECRET);

        try 
        {
            consumer.sign(request);
        } 
        catch (OAuthMessageSignerException e) 
        {

        } 
        catch (OAuthExpectationFailedException e) 
        {
        } 
        catch (OAuthCommunicationException e) 
        {
        }
        HttpClient client = new DefaultHttpClient();
        //finally execute this request
        try 
        {
            HttpResponse response = client.execute(request, context);
            HttpEntity responseEntity = response.getEntity(); 
            if (responseEntity != null) 
            { 
                Log.d(TAG, "responseEntety!=null");
                try 
                {
                    Log.d(TAG, EntityUtils.toString(responseEntity));
                } 
                catch (ParseException e) 
                {
                    e.printStackTrace();
                    Log.e(TAG, e.toString());
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                    Log.e(TAG, e.toString());
                } // gives me {"meta":{"status":401,"msg":"Not Authorized"},"response":[]} when I try to upload a photo
            }
            else
            {
                Log.d(TAG, "responseEntety==null");
            }
        } 
        catch (ClientProtocolException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    PostToTumblr.this.finish();
}

正如您在此处所见http://www.tumblr.com/blog/snapnowandroid(至少截至目前为止)已发布“这只是一个测试”的文字。

但是,当我尝试发布图片时,它会变得奇怪。现在我已经检查了一下,显然这是tumblr API的一个众所周知的问题,已经过度讨论了here,有些已经用其他编程语言解决了它(例如here),但我一直在无法重复这些成功。

该方法(以下整体)与上述方法具有完全相同的结构(有效),nameValuePairs只是不同

该方法被赋予一个名为photo:

的Bitmap变量
    private void uploadToTumblr(Bitmap photo)

此位图转换为数组:

ByteArrayOutputStream stream = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();

nameValuePairs填写如下:

nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("type", enc), URLEncoder.encode("photo", enc)));
nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("caption", enc), URLEncoder.encode(text, enc))); 
nameValuePairs.add(new BasicNameValuePair("data", Base64.encodeToString(bytes, Base64.URL_SAFE))); 

结果是来自tumblr api的{"meta":{"status":400,"msg":"Bad Request"},"response":{"errors":["Error uploading photo."]}}

我尝试按照this article中的描述对图片进行不同的编码,但没有任何更改。

//http://www.coderanch.com/t/526487/java/java/Java-Byte-Hex-String
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 3];
int v;
for ( int j = 0; j < bytes.length; j++ ) 
{
    v = bytes[j] & 0xFF;
    hexChars[j * 3] = '%';
    hexChars[j * 3 + 1] = hexArray[v >>> 4];
    hexChars[j * 3 + 2] = hexArray[v & 0x0F];
}
String s = new String(hexChars);                
s = URLEncoder.encode(s, enc);
nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("data", enc), s)); 

这里是整个方法(没有十六进制编码):

private void uploadToTumblr(Bitmap photo)
{
    if(!OAUTH_TOKEN.equals(""))
    {

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byte[] bytes = stream.toByteArray();

        String text ="SNAP";


        HttpContext context = new BasicHttpContext();
        HttpPost request = new HttpPost("http://api.tumblr.com/v2/blog/" + blogname + ".tumblr.com/post");

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); 
        String enc = "UTF-8"; 

        try 
        {
            nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("type", enc), URLEncoder.encode("photo", enc)));
            nameValuePairs.add(new BasicNameValuePair(URLEncoder.encode("caption", enc), URLEncoder.encode(text, enc))); 
            nameValuePairs.add(new BasicNameValuePair("data", Base64.encodeToString(bytes, Base64.URL_SAFE))); 
        } 
        catch (UnsupportedEncodingException e2) 
        {
            Log.e(TAG, e2.toString());
            e2.printStackTrace();
        } 
        try 
        {
            request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        } 
        catch (UnsupportedEncodingException e1) 
        {
            Log.e(TAG, e1.toString());
            e1.printStackTrace();
        }

        if (consumer == null)
        {
            consumer = new CommonsHttpOAuthConsumer(OAuthConstants.TUMBR_CONSUMERKEY, OAuthConstants.TUMBR_SECRETKEY);
        }
        if (OAUTH_TOKEN == null || OAUTH_SECRET == null)
        {
            //throw new LoginErrorException(LoginErrorException.NOT_LOGGED_IN);
            Log.e(TAG, "Not logged in error");
        }
        consumer.setTokenWithSecret(OAUTH_TOKEN, OAUTH_SECRET);

            try 
            {
                consumer.sign(request);
            } 
            catch (OAuthMessageSignerException e) 
            {

            } 
            catch (OAuthExpectationFailedException e) 
            {

            } 
            catch (OAuthCommunicationException e) 
            {
            }

            HttpClient client = new DefaultHttpClient();

            //finally execute this request
            try 
            {
                HttpResponse response = client.execute(request, context);
                HttpEntity responseEntity = response.getEntity(); 
                if (responseEntity != null) 
                { 
                    Log.d(TAG, "responseEntety!=null");
                    try 
                    {
                        Log.d(TAG, EntityUtils.toString(responseEntity));
                    } 
                    catch (ParseException e) 
                    {
                        e.printStackTrace();
                        Log.e(TAG, e.toString());
                    } 
                    catch (IOException e) 
                    {
                        e.printStackTrace();
                        Log.e(TAG, e.toString());
                    } 
                }
                else
                {
                    Log.d(TAG, "responseEntety==null");
                }
            } 
            catch (ClientProtocolException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


    }

    else
    {
        Log.d(TAG, "upload imposble... Toklen not set");
    }
    PostToTumblr.this.finish();
}

现在,虽然有几件我不满意的事情(例如,这是使用活动而不是服务完成的),但这里的重大问题显然是上传图片的问题。我绝不是第一个遇到这个问题的人,所以有人能够在java中完成这个吗?

修改1

手头的问题没有取得任何进展,但创造了一个可能对遇到同样问题的人有用的解决方法。 Tumblr提供posting via mail,您可以将android编程为在后台发送电子邮件shown here。这非常有效,但您需要让用户提供他们的邮件帐户数据和Tumblr-mail Adress才能发布。

修改2

多年以来,使用电子邮件不再是简单的方法。使用jumblr,最终有一个适用于Android的良好的Java API。 OAuth-Authentication并不好玩(它从来没有)但是一旦你超越了这个,就太棒了。

现在,从技术上讲,如何进行身份验证的问题并不属于这里,但这是我过长的问题,所以我只是在这里粘贴一些代码,如果它对你来说没什么兴趣就跳过它。

这使用名为 jumblr-0.0.10-jar-with-dependencies.jar

的jar
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;

import com.tumblr.jumblr.JumblrClient;
import com.tumblr.jumblr.request.RequestBuilder;
import com.tumblr.jumblr.types.Blog;
import com.tumblr.jumblr.types.User;

import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.TumblrApi;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;

import java.io.File;


public class Tumblr
{
private static final String PROTECTED_RESOURCE_URL = "http://api.tumblr.com/v2/user/info";

static OAuthService service;
static Token requestToken=null;


public static void share(final Activity ctx, File file)
{
    Thread tt = new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            JumblrClient client = new JumblrClient(Tumblr_Constants.CONSUMER_KEY, Tumblr_Constants.CONSUMER_SECRET);
            RequestBuilder requestBuilder = client.getRequestBuilder();
            requestBuilder.setConsumer(Tumblr_Constants.CONSUMER_KEY, Tumblr_Constants.CONSUMER_SECRET);
            SharedPreferences settings = ctx.getSharedPreferences("TumblrData", 0);
            String oauthToken=settings.getString("OauthToken", "");
            String oauthTokenSecret=settings.getString("OauthSecret", "");
            if(oauthToken.equals("") || oauthTokenSecret.equals(""))
            {
                authenticate(ctx);
                while(WebViewFragment.verifier.equals(""))
                {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                String v = WebViewFragment.verifier;
                Token accessToken = authenticatefurther(v);
                SharedPreferences.Editor edit = settings.edit();
                edit.putString("OauthToken", accessToken.getToken());
                edit.putString("OauthSecret", accessToken.getSecret());
                edit.commit();
                oauthToken=settings.getString("OauthToken", "");
                oauthTokenSecret=settings.getString("OauthSecret", "");
            }
            if(!oauthToken.equals("") && !oauthTokenSecret.equals(""))
            {
                client.setToken(oauthToken, oauthTokenSecret);

                User user = client.user();
                System.out.println(user.getName());

                for (Blog blog : user.getBlogs()) {
                    Log.d("TUMBLR", blog.getTitle());
                }
            }
        }

    });
    tt.start();

}

private static void authenticate(Context ctx) {
    service = new ServiceBuilder()
            .provider( TumblrApi.class )
            .apiKey(Tumblr_Constants.CONSUMER_KEY)
            .apiSecret(Tumblr_Constants.CONSUMER_SECRET)
            .callback("snapnao://snapnao.de/ok") // OOB forbidden. We need an url and the better is on the tumblr website !
            .build();


    Log.d("TUMBLR", "=== Tumblr's OAuth Workflow ===" );
    System.out.println();

    // Obtain the Request Token
    Log.d("TUMBLR", "Fetching the Request Token...");
    requestToken = service.getRequestToken();
    Log.d("TUMBLR", "Got the Request Token!");
    Log.d("TUMBLR", "");

    Log.d("TUMBLR", "Now go and authorize Scribe here:" );
    Log.d("TUMBLR", service.getAuthorizationUrl( requestToken ) );

    String url = service.getAuthorizationUrl(requestToken);


    Intent i = new Intent(ctx, WebViewFragment.class);
    i.putExtra("url", url);
    ctx.startActivity(i);


}

private static Token authenticatefurther(String v)
{
    Token accessToken = null;
    Log.d("TUMBLR", "And paste the verifier here");
    Log.d("TUMBLR", ">>");

    Verifier verifier = new Verifier( v);
    Log.d("TUMBLR", "");

    // Trade the Request Token and Verfier for the Access Token
    Log.d("TUMBLR", "Trading the Request Token for an Access Token...");
    accessToken = service.getAccessToken( requestToken ,
            verifier );
    Log.d("TUMBLR", "Got the Access Token!");
    Log.d("TUMBLR", "(if your curious it looks like this: " + accessToken + " )");

    Log.d("TUMBLR", "");

    return accessToken;
}


}

WebViewFragement看起来像这样:

import android.app.Activity;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Bundle;
import android.util.Log;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;


public class WebViewFragment extends Activity 
{
public static String verifier="";
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.webviewfragment);

    String url = getIntent().getStringExtra("url");
    Log.d("TUMBLR", "webview-> "+url);
    WebView view = (WebView) findViewById(R.id.webView);
    view.setWebViewClient(
            new SSLTolerentWebViewClient()
    );
    view.getSettings().setJavaScriptEnabled(true);
    view.loadUrl(url);
}

// SSL Error Tolerant Web View Client
private class SSLTolerentWebViewClient extends WebViewClient {

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed(); // Ignore SSL certificate errors
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        Log.d("TUMBLR", "+++++"+url);
        if(url.contains("oauth_verifier="))
        {
            String[] x = url.split("oauth_verifier=");
            verifier=x[1].replace("#_=_", "");
            WebViewFragment.this.finish();
        }
    }
}
}

5 个答案:

答案 0 :(得分:3)

为什么不使用Jumblr Tumblr的官方Java客户端。

问候。

答案 1 :(得分:3)

您可以使用jumblr - Tumblr java客户端

轻松完成此操作
JumblrClient client = new JumblrClient(Constant.CONSUMER_KEY,Constant.CONSUMER_SECRET);

client.setToken(preferences.getString("token",null), preferences.getString("token_secret", null));

PhotoPost pp = client.newPost(client.user().getBlogs().get(0).getName(),PhotoPost.class);

pp.setCaption(caption);
// pp.setLinkUrl(link);
// pp.setSource(mImage); // String URL
pp.setPhoto(new Photo(imgFile));
pp.save();

答案 2 :(得分:0)

这对我有用......

nameValuePairs.add(new BasicNameValuePair(URLEncoder
                .encode("type", "UTF-8"),
                     URLEncoder.encode("photo", "UTF-8")));
Log.e("Tumblr", "Image shareing file path" + filePath);
nameValuePairs.add(new BasicNameValuePair("caption", caption));
nameValuePairs.add(new BasicNameValuePair("source", filePath));`

其中filePath是http url。

答案 3 :(得分:0)

我使用了以下方法。你可以试试这个。

// paramString =“你想放入标题的文字”

private void postPhotoTumblr(String uploadedImagePhotoUrl, String paramString)
{
  CommonsHttpOAuthConsumer localCommonsHttpOAuthConsumer = getTumblrConsumer();
  String str1 = "logged in username";
  String encodedImage = uploadedImagePhotoUrl;
  DefaultHttpClient localDefaultHttpClient = new DefaultHttpClient();
  HttpPost localHttpPost = new HttpPost("http://api.tumblr.com/v2/blog/" + str1 + ".tumblr.com/post");
  try
  {

    ArrayList localArrayList = new ArrayList();
    localArrayList.add(new BasicNameValuePair("type", "photo"));
    BasicNameValuePair localBasicNameValuePair = new BasicNameValuePair("caption", paramString);
    localArrayList.add(localBasicNameValuePair);
    localArrayList.add(new BasicNameValuePair("data",encodedImage));
    UrlEncodedFormEntity localUrlEncodedFormEntity = new UrlEncodedFormEntity(localArrayList);
    localHttpPost.setEntity(localUrlEncodedFormEntity);
    localCommonsHttpOAuthConsumer.sign(localHttpPost);
    InputStream localInputStream = localDefaultHttpClient.execute(localHttpPost).getEntity().getContent();
    InputStreamReader localInputStreamReader = new InputStreamReader(localInputStream);
    BufferedReader localBufferedReader = new BufferedReader(localInputStreamReader);
    StringBuilder localStringBuilder = new StringBuilder();
    while (true)
    {
      String str2 = localBufferedReader.readLine();
      if (str2 == null)
      {
        Log.i("DATA post resp", localStringBuilder.toString());
        break;
      }
      localStringBuilder.append(str2);
    }
  }
  catch (ClientProtocolException localClientProtocolException)
  {
    localClientProtocolException.printStackTrace();
  }
  catch (IOException localIOException)
  {
    localIOException.printStackTrace();
  }
  catch (OAuthMessageSignerException localOAuthMessageSignerException)
  {
    localOAuthMessageSignerException.printStackTrace();
  }
  catch (OAuthExpectationFailedException localOAuthExpectationFailedException)
  {
    localOAuthExpectationFailedException.printStackTrace();
  }
  catch (OAuthCommunicationException localOAuthCommunicationException)
  {
    localOAuthCommunicationException.printStackTrace();
  }
}

编辑:首先将图像上传到Web Server,然后获取Url并尝试使用上传的Url或文件路径发布。它会工作得很好......:)

答案 4 :(得分:0)

我使用了multipart 公共类VideoUploader扩展了AsyncTask {

    ProgressDialog progressDialog;

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        progressDialog = ProgressDialog.show(RecordingActivity.this, "",
                "Uploading video.. ");
        super.onPreExecute();
    }

    @Override
    protected JSONObject doInBackground(String... params) {
        JSONObject jsonObject = null;
        StringBuilder builder = new StringBuilder();
        try {
            String url = UrlConst.VIDEO_URL;
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(url);

            FileBody filebodyVideo = new FileBody(new File(params[0]));
            StringBody title = new StringBody("uploadedfile: " + params[0]);
            StringBody description = new StringBody(
                    "This is a video of the agent");
            // StringBody code = new StringBody(realtorCodeStr);

            MultipartEntity reqEntity = new MultipartEntity();
            reqEntity.addPart("uploadedfile", filebodyVideo);
            reqEntity.addPart("title", title);
            reqEntity.addPart("description", description);
            // reqEntity.adddPart("code", code);
            httppost.setEntity(reqEntity);

            // DEBUG
            System.out.println("executing request "
                    + httppost.getRequestLine());
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity resEntity = response.getEntity();

            // DEBUG
            StatusLine status = response.getStatusLine();
            int statusCode = status.getStatusCode();
            System.out.println(response.getStatusLine());
            if (resEntity != null) {
                System.out.println(EntityUtils.toString(resEntity));
            } // end if

            if (resEntity != null) {
                resEntity.consumeContent();
            } // end if
            if (statusCode == 200) {
                InputStream content = resEntity.getContent();
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(content));
                String line;
                while ((line = reader.readLine()) != null) {
                    builder.append(line);
                }
                jsonObject = new JSONObject(builder.toString());
                return jsonObject;
            } else {
                Log.e(LoginActivity.class.toString(),
                        "Failed to download file");
            }
            httpclient.getConnectionManager().shutdown();

        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }

    @Override
    protected void onPostExecute(JSONObject result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        progressDialog.dismiss();
        if (result != null) {

            try {

                JSONObject jsonObject = result
                        .getJSONObject(ParsingTagConst.COMMANDRESULT);
                String strSuccess = jsonObject
                        .getString(ParsingTagConst.SUCCESS);
                String responseString = jsonObject
                        .getString(ParsingTagConst.RESPONSE_STRING);
                Toast.makeText(RecordingActivity.this, "" + responseString,
                        Toast.LENGTH_LONG).show();
                if (strSuccess.equals("1")) {
                    // get here your response
                }

            } catch (Exception e) {
                // TODO: handle exception
            }
        }

    }

}



enter code here