Android SDK 只包含了最终用户使用场景中的必要功能。相比服务端 SDK 而言,客户端 SDK 不会包含对云存储服务的管理和配置功能。

安装

直接安装

将sdk jar文件 复制到项目中去,jar包下载地址 , 下载对应的jar包,以及搜索下载对应的依赖库

通过maven

Android Studio中添加dependencies 或者 在项目中添加maven依赖

// 1 直接导入
implementation 'com.qiniu:qiniu-android-sdk:8.0.+'// 2 如果要修改okhttp依赖的版本,可采用以下方式(强烈建议使用七牛库依赖的okhttp版本)implementation ('com.qiniu:qiniu-android-sdk:8.0.+'){exclude (group: 'com.squareup.okhttp3', module: 'okhttp')}
implementation 'com.squareup.okhttp3:okhttp:4.2.2'如果是eclipse, 也可以直接添加依赖来处理。

相关链接

如果需要下载历史 jar 包,也可以在 maven 上直接下载,请参考这里。

安全机制

该 SDK 未包含凭证生成相关的功能。开发者对安全性的控制应遵循安全机制中建议的做法,即客户端应向业务服务器每隔一段时间请求上传凭证,而不是直接在客户端使用 AccessKey / SecretKey 生成对应的凭证。在客户端使用 SecretKey 会导致严重的安全隐患。

开发者可以在生成上传凭证前通过配置上传策略来控制上传的后续动作,例如在上传完成后通过回调机制通知业务服务器。该工作在业务服务器端进行,因此非本 SDK 的功能范畴。

存储的服务端SDK提供了上传凭证的生成功能,请参考各个服务端语言的SDK文档。

初始化

一般情况下可以直接使用默认设置,不用单独配置。可以配置超时时长、分片上传阀值等。

Configuration config = new Configuration.Builder()
.connectTimeout(90) // 链接超时。默认90秒
.useHttps(true) // 是否使用https上传域名.useConcurrentResumeUpload(true) // 使用并发上传,使用并发上传时,除最后一块大小不定外,其余每个块大小固定为4M,
.concurrentTaskCount(3) // 并发上传线程数量为3
.responseTimeout(90) // 服务器响应超时。默认90秒
.recorder(recorder) // recorder分片上传时,已上传片记录器。默认null
.recorder(recorder, keyGen) // keyGen 分片上传时,生成标识符,用于片记录器区分是那个文件的上传记录
.zone(FixedZone.zone0) // 设置区域,不指定会自动选择。指定不同区域的上传域名、备用域名、备用IP。
.build();
// 重用uploadManager。一般地,只需要创建一个uploadManager对象
UploadManager uploadManager = new UploadManager(config);
版本
Qiniu SDK 版本
最低 Android版本
依赖库版本
8.0.x
Android 5.0+
okhttp 4+7.6.x
Android 5.0+
okhttp 4+7.5.x
Android 5.0+
okhttp 4+7.4.6
Android 4.0+
okhttp 3.12.67.3.x
Android 2.3+
okhttp 3.11.07.2.x
Android 2.3+
okhttp 3+7.1.x
Android 2.3+
okhttp 2.6+7.0.8,7.0.9
Android 2.2+
android-async-http 1.4.97.0.7
Android 2.2+
android-async-http 1.4.8注意
推荐使用最新版:8.0.3
AndroidNetwork.getMobileDbm()可以获取手机信号强度,需要如下权限(API>=18时生效)
从7.5.0开始增加了DNS预取和缓存策略,减少dns解析错误
如果可以明确 区域 的话,最好指定固定区域,这样可以少一步网络请求,少一步出错的可能。
下方为8.x使用外部 dns 组件 httpDns 的示例代码:import com.qiniu.android.http.Dns;class DemoDnsNetworkAddress implements IDnsNetworkAddress {
private final String hostValue;
private final String ipValue;
private final Long ttlValue;
private final String sourceValue;
private final Long timestampValue;
DemoDnsNetworkAddress(String hostValue,
String ipValue,
Long ttlValue,
String sourceValue,
Long timestampValue) {
this.hostValue = hostValue;
this.ipValue = ipValue;
this.ttlValue = ttlValue;
this.sourceValue = sourceValue;
this.timestampValue = timestampValue;
}
@Override
public String getHostValue() {
return hostValue;
}
@Override
public String getIpValue() {
return ipValue;
}
@Override
public Long getTtlValue() {
return ttlValue;
}
@Override
public String getSourceValue() {
return sourceValue;
}
@Override
public Long getTimestampValue() {
return timestampValue;
}
}
public Dns buildDefaultDns() {
// 可添加修改 多个 IResolver
// 适当调整不同 IResolver 的加入顺序,比如:223.5.5.5,119.29.29.29,114.114.114.114,8.8.8.8 等
ArrayList rs = new ArrayList(3);
try {
IResolver r1 = new Resolver(InetAddress.getByName("119.29.29.29"));
rs.add(r1);
} ctch (Exception ex) {
ex.printStackTrace();
}
try {
rs.add(new Resolver(InetAddress.getByName("114.114.114.114")));
} catch (Exception ex) {
ex.printStackTrace();
}
try {
// 读取系统相关属性
// android 27 及以上 会报错
IResolver r2 = AndroidDnsServer.defaultResolver();
rs.add(r2);
} catch (Exception ex) {
ex.printStackTrace();
}
if (rs.size() == 0) {
return null;
}
final DnsManager happlyDns = new DnsManager(NetworkInfo.normal, rs.toArray(new IResolver[rs.size()]));
Dns dns = new Dns() {
// 若抛出异常 Exception ,sdk 会使用 okhttp 组件默认 dns 解析结果@Override
public List lookup(String hostname) throws UnknownHostException {
Domain domain = new Domain(hostname);
List addressList = null;
try {
Record[] records = dnsManager.queryRecords(domain);
if (records != null && records.length > 0){
addressList = new ArrayList<>();
for (Record record : records) {
String source = "customized";
DemoDnsNetworkAddress address = new DemoDnsNetworkAddress(hostname, record.value, (long)record.ttl, source, record.timeStamp);
addressList.add(address);
}
}
} catch (IOException ignored) {
}
return addressList;
}
};
return dns;
}
GlobalConfiguration.getInstance().dns = buildDefaultDns();
uploadManager = new UploadManager();
上传文件
SDK 内置两种上传方式:表单上传和分片上传,并根据具体情况,内部做了自动切换。表单上传使用一个 HTTP POST 请求完成文件的上传,因此比较适合较小的文件和较好的网络环境。相比而言,分片上传更能适应不稳定的网络环境,也比较适合上传比较大的文件(例如数百 MB 或更大)。
若需深入了解上传方式之间的区别,请参阅上传类型中表单上传和分片上传接口说明。
UploadManager.put 参数说明:
参数
类型
说明
data
byte[]/String/File
数据,可以是 byte 数组、文件路径、文件
key
String
保存在服务器上的资源唯一标识,请参阅键值对
token
String
服务器分配的 token
completionHandlerUpCompletionHandler
上传回调函数,必填
options
UploadOptions
如果需要进度通知、中途取消、指定 mimeType,则需要填写相应字段,详见下面的 UploadOptions 参数说明
UploadOptions 参数说明:
参数
类型
说明
params
Map
自定义变量,key 必须以 x: 开始
mimeType
String
指定文件的 mimeType
progressHandler
UpProgressHandler
上传进度回调
cancellationSignal
UpCancellationSignal
取消上传,当 isCancelled() 返回 true 时,不再执行更多上传
简单上传
//指定zone的具体区域
//FixedZone.zone0 华东机房
//FixedZone.zone1 华北机房
//FixedZone.zone2 华南机房
//FixedZone.zoneNa0 北美机房
//自动识别上传区域
//AutoZone.autoZone
//Configuration config = new Configuration.Builder()
//.zone(Zone.autoZone)
//.zone(FixedZone.zone0)
//.build();
//UploadManager uploadManager = new UploadManager(config);
data = 
String key = ;
String token = ;
uploadManager.put(data, key, token,
new UpCompletionHandler() {
@Override
public void complete(String key, ResponseInfo info, JSONObject res) {//res包含hash、key等信息,具体字段取决于上传策略的设置
if(info.isOK()) {
Log.i("qiniu", "Upload Success");
} else {
Log.i("qiniu", "Upload Fail");
//如果失败,这里可以把info信息上报自己的服务器,便于后面分析上传错误原因
}
Log.i("qiniu", key + ",\r\n " + info + ",\r\n " + res);
}
}, null);

回调参数说明:

参数

说明

key

uploadManager.put(file, key, ...) 方法指定的 key

info

http 请求的状态信息等,可记入日志,isOK() 返回 true 表示上传成功

response

存储服务反馈的信息。可从中解析保存在存储服务的 key 等信息,具体字段取决上传策略的设置

注意:可能会抛出文件不存在,没有权限访问等异常。

上传进度
uploadManager.put(data, key, token,handler,
new UploadOptions(null, null, false,
new UpProgressHandler(){
public void progress(String key, double percent){
Log.i("qiniu", key + ": " + percent);
}
}, null));
注意:progress(key, percent) 中的 key 即 uploadManager.put(file, key, ...) 方法指定的 key。
取消上传
内部代码会检测 UpCancellationSignal##isCancelled() 的返回值,当其返回 true 时,将停止上传。可外部维护一个变量 isCancelled,当点击取消按钮时,设置 isCancelled = true; 。例如:
// 初始化、执行上传
private volatile boolean isCancelled = false;
uploadManager.put(data, key, token,handler,
new UploadOptions(null, null, false, progressHandler,
new UpCancellationSignal(){
public boolean isCancelled(){
return isCancelled;
}
}));
// 点击取消按钮,让UpCancellationSignal##isCancelled()方法返回true,以停止上传
private void cancell() {
isCancelled = true;
}

记录断点

分片上传中,可将各个已上传的块记录下来,再次上传时,已上传的部分不用再次上传。断点记录类需实现 com.qiniu.android.storage.Recorder 接口。已提供保存到文件的 FileRecorder 实现。

String dirPath = 
Recorder recorder = null;
try {
recorder = new FileRecorder(dirPath);
}catch (Exception e){
}
//默认使用key的url_safe_base64编码字符串作为断点记录文件的文件名
//避免记录文件冲突(特别是key指定为null时),也可自定义文件名(下方为默认实现):
KeyGenerator keyGen = new KeyGenerator(){
public String gen(String key, File file){
// 不必使用url_safe_base64转换,uploadManager内部会处理
// 该返回值可替换为基于key、文件内容、上下文的其它信息生成的文件名
return key + "_._" + new StringBuffer(file.getAbsolutePath()).reverse();
}
};
// 重用uploadManager。一般地,只需要创建一个uploadManager对象
//UploadManager uploadManager = new UploadManager(recorder); // 1
//UploadManager uploadManager = new UploadManager(recorder, keyGen); // 2
// 或在初始化时指定:
Configuration config = new Configuration.Builder()
// recorder分片上传时,已上传片记录器
// keyGen分片上传时,生成标识符,用于片记录器区分是哪个文件的上传记录
.recorder(recorder, keyGen)
.build();
UploadManager uploadManager = new UploadManager(config);
uploadManager.put(data, key, ...)

下载文件

该 SDK 并未提供下载文件相关的功能接口,因为文件下载是一个标准的 HTTP GET 过程。开发者只需理解资源 URI 的组成格式即可非常方便的构建资源 URI,并在必要的时候加上下载凭证,即可使用 HTTP GET 请求获取相应资源。

从安全性和代码可维护性的角度考虑,我们建议下载 URL 的拼接过程也在业务服务器进行,让客户端从业务服务器请求。

线程安全性

Android 一般情况下会使用一个主线程来控制 UI,非主线程无法控制 UI,在 Android4.0+ 之后不能在主线程完成网络请求,该 SDK 是根据以上的使用场景设计,所有的网络操作均使用独立的线程异步运行,UpCompletionHandler##complete、UpProgressHandler##progress 是在主线程调用的,在回调函数内可以直接操作 UI 控件。

API 参考

常见问题

1. 混淆处理

对七牛的 SDK 不需要做特殊混淆处理,如果有混淆,请将七牛相关的包都排除。
在 Android Studio 中,混淆配置在 proguard-rules.pro 里面加上下面几行混淆代码就行:
-keep class com.qiniu.**{*;}-keep class com.qiniu.**{public ();}-ignorewarnings
注意:-ignorewarnings 这个也是必须加的,如果不加这个,编译的时候可能可以通过,但是 release 的时候还是会出现错误。
在 eclipse 中,混淆配置在 proguard-project.txt 里面加上下面几行混淆代码就行:
-keep class com.qiniu.**{*;}-keep class com.qiniu.**{public ();}-ignorewarnings

2. 为什么进度会在 95% 停很久?

因为上传进度是用 sdk 写入 socket 的字节数/总字节数作为进度,但写入 socket 不等于服务器收到并且处理完成,中间还有一段时间,如果只是用字节数就会出现更怪异的情况,在 100% 停留很久,所以综合考虑就使用了 95% 这个值。

如果您发现上传卡在 95% 很长的时间,请检查是否使用了上传回调业务服务器的功能,请确保业务服务器接受到上传回调后可以返回正确的状态码和回复内容。

3. 如何才能得到下载的 url ?

上传没有域名概念,只有 bucket ,一个 bucket 可以绑定多个域名。下载的 url 可以用 bucket 里的域名加 key 拼接而成,私有 url 还要加上 token。

4. 如何跳过 https 证书验证?

在部分测试环境发生 Trust anchor for certification path not found 异常,可以设置跳过 https 证书验证:在 Configuration 配置 useHttps(false) 开启。

相关资源

如果您有任何关于我们文档或产品的建议和想法,欢迎您通过以下方式与我们互动讨论:

技术论坛 - 在这里您可以和其他开发者愉快的讨论如何更好的使用七牛云服务

提交工单 - 如果您的问题不适合在论坛讨论或希望及时解决,您也可以提交一个工单,我们的技术支持人员会第一时间回复您

博客 - 这里会持续更新发布市场活动和技术分享文章

贡献代码

Fork

创建您的特性分支 git checkout -b my-new-feature

提交您的改动 git commit -am 'Added some feature'

将您的修改记录提交到远程 git 仓库 git push origin my-new-feature

然后到 github 网站的该 git 远程仓库的 my-new-feature 分支下发起 Pull Request

许可证

Copyright (c) 2014 qiniu.com