【问题标题】:Uploading Images to tumblr API from Android从 Android 将图像上传到 tumblr API
【发布时间】:2012-11-30 11:29:29
【问题描述】:

假设使用Tumblr API 上传图片会很容易。它不是。 (EDIT现在是,请参阅本条目末尾的Edit 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)));

} 

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

从浏览器返回提取数据:

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();

这两个 sn-ps 中的大多数我得到了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),但我无法重复这些成功。

该方法(在下面的全部内容)与上述方法(有效)具有完全相同的结构,名称ValuePairs只是不同

该方法被赋予一个名为 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 邮件地址。

编辑 2

多年过去了,使用电子邮件不再是简单的方法。有了jumblr,终于有一个很好的Java API 可以在android 上运行。 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();
        }
    }
}
}

【问题讨论】:

  • 你为什么不像typecaption那样在名称-值对中编码data输入名称?
  • 实际上不需要对输入名称进行编码(从文章开头的文本帖子的工作代码中可以看出)这只是我试图让它工作的事情之一。为了在示例代码中清晰起见,应该再次删除它。
  • 我注意到的第一件事是您使用的是data 而不是source,但您发送的是字符串而不是数组。如果您只是上传一张照片,请尝试使用带有编码字符串的 source 或使用 data 作为带有一个编码字符串元素的数组。
  • 有人能够上传 jpg 图片。改用 Bitmap.CompressFormat.JPEG。
  • @Ally 'source' 用于图像的 URL,如果您要发送图像的实际字节,则使用 'data'。此处概述:tumblr.com/docs/en/api/v2#posting

标签: android api encoding tumblr


【解决方案1】:

您可以使用 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();

【讨论】:

  • 谢谢,eltabo 在另一个答案中提到了这一点。当我遇到这个问题时,jumblr 不存在,现在它是最好的解决方案。
【解决方案2】:

我已经使用以下方法完成了。你可以试试这个。

//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 服务器,然后获取 Url 并尝试使用上传的 Url 或文件路径发布。它肯定会正常工作... :)

【讨论】:

  • 我得到了 {"meta":{"status":400,"msg":"Bad Request"},"response":{"errors":["上传照片时出错。"]} }
  • 我可以发布这不是图片的短信。将要。你帮我PLZ
【解决方案3】:

我使用了多部分 公共类 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

【讨论】:

    【解决方案4】:

    这对我有用...

    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。

    【讨论】:

    • 感谢您的回答。我已经提交了一个编辑来整理格式 - 在提问或回答问题时,如果你用四个空格缩进代码而不是使用重音符号会更整洁,因为它们不尊重你的换行符。
    • 我得到了:{"meta":{"status":400,"msg":"Bad Request"},"response":{"errors":["上传照片时出错。"] }}
    【解决方案5】:

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

    问候。

    【讨论】:

    • 从提交历史中我了解到,当我发布问题时它并不存在。现在看来值得一看。谢谢。
    • 哎呀,也许我以为你有一个通量电容器:D
    • 我尝试了 Jumblr,但无法上传图片...stackoverflow.com/questions/26271523/…
    猜你喜欢
    • 1970-01-01
    • 2012-04-30
    • 2015-07-30
    • 1970-01-01
    • 2014-08-26
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 2014-07-03
    相关资源
    最近更新 更多