Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name=".demo.MyActivity"
android:theme="@android:style/Theme.Light.NoTitleBar"
Expand All @@ -14,5 +15,10 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".demo.MyResumableActivity"
android:theme="@android:style/Theme.Light.NoTitleBar"
android:label="@string/app_name_resumable">

</activity>
</application>
</manifest>
3 changes: 3 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
title: Android SDK 使用指南
---

- Android SDK 下载地址:<https://github.com/qiniu/android-sdk/tags>
- Android SDK 源码地址:<https://github.com/qiniu/android-sdk> (请注意非 master 分支的代码在规格上可能承受变更)

此 Android SDK 基于 [七牛云存储官方API](http://docs.qiniu.com/api/index.html) 构建。在开发者的 Android App 工程项目中使用此 SDK 能够非常方便地将 Android 系统里边的文件快速直传到七牛云存储。

出于安全考虑,使用此 SDK 无需设置密钥(AccessKey / SecretKey)。所有涉及到授权的操作,比如生成上传授权凭证(uploadToken)或下载授权凭证(downloadToken)均在业务服务器端进行。
Expand Down
6 changes: 6 additions & 0 deletions res/layout/main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,11 @@
android:id="@+id/textView1"
android:layout_marginBottom="20dp"
android:layout_centerHorizontal="true" android:layout_above="@+id/button1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="断点续上传"
android:id="@+id/button"
android:layout_alignParentRight="true" android:layout_alignParentBottom="true"/>
</RelativeLayout>

50 changes: 50 additions & 0 deletions res/layout/resumable.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="8dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择文件并上传"
android:id="@+id/button1"
android:layout_alignParentRight="true" android:layout_alignParentBottom="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="20sp"
android:layout_marginTop="20dp"
android:text="断点续上传"
android:id="@+id/textView" android:layout_alignParentTop="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView1"
android:layout_marginBottom="20dp"
android:layout_centerHorizontal="true" android:layout_above="@+id/button1"/>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
style="?android:attr/progressBarStyleHorizontal"
android:id="@+id/progressBar"
android:layout_centerVertical="true" android:indeterminate="false"
android:layout_alignRight="@+id/button1" android:layout_alignParentLeft="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停"
android:id="@+id/button2" android:layout_toLeftOf="@+id/button1" android:layout_alignTop="@+id/button1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView2" android:layout_alignLeft="@+id/progressBar"
android:layout_above="@+id/progressBar"/>
</RelativeLayout>

1 change: 1 addition & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">android-sdk</string>
<string name="app_name_resumable">android-sdk-resumable</string>
</resources>
10 changes: 7 additions & 3 deletions src/com/qiniu/auth/CallRet.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.qiniu.auth;

public abstract class CallRet {
import com.qiniu.utils.IOnProcess;

public abstract class CallRet implements IOnProcess {
public void onInit(int flag){}
public abstract void onSuccess(byte[] body);
public abstract void onFailure(Exception ex);
public void onSuccess(){}
}
public void onProcess(long current, long total){}
public void onPause(Object tag){}
}
120 changes: 72 additions & 48 deletions src/com/qiniu/auth/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

import android.os.AsyncTask;
import com.qiniu.conf.Conf;
import com.qiniu.utils.ICancel;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
Expand All @@ -19,86 +24,106 @@
import java.io.IOException;

public class Client {

protected HttpClient mClient;

public Client(HttpClient client) {
mClient = client;
}

public void call(String url, CallRet ret) {
HttpPost httppost = new HttpPost(url);
execute(httppost, ret);
public static ClientExecutor get(String url, CallRet ret) {
Client client = Client.defaultClient();
return client.get(client.makeClientExecutor(), url, ret);
}

public void call(String url, HttpEntity entity, CallRet ret) {
call(url, entity.getContentType().getValue(), entity, ret);
public ClientExecutor call(ClientExecutor client, String url, HttpEntity entity, CallRet ret) {
Header header = entity.getContentType();
String contentType = "application/octet-stream";
if (header != null) {
contentType = header.getValue();
}
return call(client, url, contentType, entity, ret);
}

public void call(String url, String contentType, HttpEntity entity, CallRet ret) {
public ClientExecutor call(ClientExecutor client, String url, String contentType, HttpEntity entity, CallRet ret) {
HttpPost httppost = new HttpPost(url);
httppost.setEntity(entity);

if (contentType != null) {
httppost.setHeader("Content-Type", contentType);
}
execute(httppost, ret);
return execute(client, httppost, ret);
}

public ClientExecutor get(ClientExecutor client, String url, CallRet ret) {
return execute(client, new HttpGet(url), ret);
}

protected void execute(HttpPost httpPost, CallRet ret) {
new ClientExecuter().execute(httpPost, ret);
public ClientExecutor makeClientExecutor() {
return new ClientExecutor();
}

protected HttpResponse roundtrip(HttpPost httpPost) throws IOException {
httpPost.setHeader("User-Agent", Conf.USER_AGENT);
return mClient.execute(httpPost);
protected ClientExecutor execute(ClientExecutor client, HttpRequestBase httpRequest, final CallRet ret) {
client.setup(httpRequest, ret);
client.execute();
return client;
}

protected HttpResponse roundtrip(HttpRequestBase httpRequest) throws IOException {
httpRequest.setHeader("User-Agent", Conf.USER_AGENT);
return mClient.execute(httpRequest);
}

class ClientExecuter extends AsyncTask<Object, Object, Object> {
HttpPost httpPost;
CallRet ret;
public class ClientExecutor extends AsyncTask<Object, Object, Object> implements ICancel {
HttpRequestBase mHttpRequest;
CallRet mRet;
public void setup(HttpRequestBase httpRequest, CallRet ret) {
mHttpRequest = httpRequest;
mRet = ret;
}
public void upload(long current, long total) {
publishProgress(current, total);
}

@Override
protected Object doInBackground(Object... objects) {
httpPost = (HttpPost) objects[0];
ret = (CallRet) objects[1];
String errMsg = "";

HttpResponse resp;
try {
resp = roundtrip(httpPost);
HttpResponse resp = roundtrip(mHttpRequest);
int statusCode = resp.getStatusLine().getStatusCode();
if (statusCode == 401) { // android 2.3 will not response
return new Exception("unauthorized!");
}
byte[] data = EntityUtils.toByteArray(resp.getEntity());

if (statusCode / 100 != 2) {
if (data.length == 0) {
String xlog = resp.getFirstHeader("X-Log").getValue();
if (xlog.length() > 0) {
return new Exception(xlog);
}
return new Exception(resp.getStatusLine().getReasonPhrase());
}
return new Exception(new String(data));
}
return data;
} catch (IOException e) {
e.printStackTrace();
return e;
}
}

if (resp.getHeaders("X-Log").length > 0) {
errMsg = resp.getHeaders("X-Log")[0].getValue();
}

int statusCode = resp.getStatusLine().getStatusCode();

if (statusCode / 100 != 2) {
return new Exception(errMsg);
}

byte[] data = new byte[0];
try {
data = EntityUtils.toByteArray(resp.getEntity());
} catch (IOException e) {
e.printStackTrace();
}

return data;
@Override
protected void onProgressUpdate(Object... values) {
mRet.onProcess((Long) values[0], (Long) values[1]);
}

@Override
protected void onPostExecute(Object o) {
if (o instanceof Exception) {
ret.onFailure((Exception) o);
mRet.onFailure((Exception) o);
return;
}
ret.onSuccess((byte[]) o);
mRet.onSuccess((byte[]) o);
}
};

Expand All @@ -107,11 +132,10 @@ public static Client defaultClient() {
}

public static HttpClient getMultithreadClient() {
HttpParams params = new BasicHttpParams();
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
HttpClient client = new DefaultHttpClient(cm, params);
HttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
return client;
}
}
4 changes: 4 additions & 0 deletions src/com/qiniu/auth/JSONObjectRet.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import org.json.JSONObject;

public abstract class JSONObjectRet extends CallRet {
public JSONObjectRet(){}
protected int mIdx;
public JSONObjectRet(int idx) { mIdx = idx; }
@Override
public void onSuccess(byte[] body) {
if (body == null) {
Expand All @@ -13,6 +16,7 @@ public void onSuccess(byte[] body) {
JSONObject obj = new JSONObject(new String(body));
onSuccess(obj);
} catch (JSONException e) {
e.printStackTrace();
onFailure(new Exception(new String(body)));
}
}
Expand Down
32 changes: 0 additions & 32 deletions src/com/qiniu/auth/UpClient.java

This file was deleted.

Loading