赞
踩
自开发一个Android APP,只有自己一个人进行使用,想直接从OSS上下载文件做解析,但是阿里云提供给Android的SDK,必须要通过STS的嫁接,
即必须要有一台服务器,用于获取token,其不推荐由APP直接使用ACCESS_KEY_ID与ACCESS_KEY_SECRET直接对OSS进行访问,因为认为APP是不安全的,
但是对于这种私人使用的,apk仅安装在自己手机上的,还需要一台服务器的嫁接,未免有成本所在,
不论是服务端的SDK还是Android的SDK,本质都是最终拼接一些参数,使用HTTP协议发送过去,因此只需要了解需要发送哪些参数可以正确读到资源就好,
我的业务是读取资源:GetObject - 对象存储 OSS - 阿里云
如下图可以看到,读取一个资源本质就是发起一个get请求,同时在Http Header头部带上Host、Date、Authorization。
阿里云的HTTP协议文档:使用REST API发起请求 - 对象存储 OSS - 阿里云
Authorization的签名方式:
我在经过对url、Date、Authorization的调参后,成功使用PostMan下载到了文件,由此可以说明,我们在Android中也可以通过一样的方式去下载到OSS中的文件。
如果要手动编码,需要很多东西,因此我还是依赖了阿里提供给Server端的SDK,用作签名使用,发起Http请求则是使用的OkHTTP3,
为什么不用HttpClient?因为我本以为直接用阿里给Server端的SDK也就是aliyun-sdk-oss可以直接请求,却发现在Android中报错如下:
- No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier;
-
- in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier;
-
- or its superclasses (declaration of 'org.apache.http.conn.ssl.AllowAllHostnameVerifier' appears in /system/framework/framework.jar!classes3.dex)
最终看到一个老外说,该库可能并不是提供给Android端使用的,虽然看错误是某个字段不存在,貌似framework中内置该jar,因为先加载的是framework.jar中的,所以aliyun-sdk-oss内置的httpclient不会被加载,
这个问题我最终没有找出来,因此姑且认为aliyun-sdk-oss真的没法在Android端使用,当然如果读者可以解决这个库在Android上的这个问题,那么aliyun-sdk-oss就可以直接使用,没必要自己手写API对接OSS这么麻烦,有解决方法也请告诉我。
下面,我依赖的两个库:
- implementation 'com.aliyun.oss:aliyun-sdk-oss:3.15.1'
- implementation 'com.squareup.okhttp3:okhttp:4.10.0'
实现代码:
需要注意的是,这里需要你改的几个地方:BUCKET、END_POINT、ACCESS_KEY_ID、ACCESS_KEY_SECRET,这几个字段请改成你自己阿里云OSS的配置。
- private static final String BUCKET = "your bucket";
- private static final String END_POINT = "your end point";
- private static final String ACCESS_KEY_ID = "your ACCESS_KEY_ID";
- private static final String ACCESS_KEY_SECRET = "your ACCESS_KEY_SECRET";
- private static final String DATE = "Date";
- private static final String AUTHORIZATION = "Authorization";
-
- private static String getEndPoint() {
- return "https://" + BUCKET + "." + END_POINT;
- }
-
- private static String getEndPoint(String aliFileName) {
- return getEndPoint() + "/" + aliFileName;
- }
-
- private static String getResourceName(String aliFileName) {
- return "/" + BUCKET + "/" + aliFileName;
- }
-
- private static String getGmtTime() {
- Calendar cd = Calendar.getInstance();
- SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
- sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // 设置时区为GMT
- return sdf.format(cd.getTime());
- }
-
- public void downloadFile(String aliFileName) {
- String nowTime = getGmtTime();
- HashMap<String, String> map = new HashMap<>();
- map.put(DATE, nowTime);
- RequestMessage requestMessage = new RequestMessage(BUCKET, aliFileName);
- requestMessage.setBucket(BUCKET);
- requestMessage.setKey(aliFileName);
- requestMessage.setResourcePath(aliFileName);
- requestMessage.setMethod(HttpMethod.GET);
- requestMessage.setEndpoint(URI.create(getEndPoint()));
- requestMessage.setHeaders(map);
- String signature = SignUtils.buildSignature(ACCESS_KEY_SECRET, HttpMethod.GET.name(), getResourceName(aliFileName), requestMessage);
- String authorization = SignUtils.composeRequestAuthorization(ACCESS_KEY_ID, signature);
- Map<String, String> getHeaders = new LinkedHashMap<>();
- getHeaders.put(DATE, nowTime);
- getHeaders.put(AUTHORIZATION, authorization);
- File file = new File(this.getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), aliFileName);
- download(getEndPoint(aliFileName), file, getHeaders);
- }
-
- public static void download(String url, File file, Map<String, String> headers) {
- new Thread(() -> {
- try {
- OkHttpClient client = new OkHttpClient();
- Request.Builder requestBuilder = new Request.Builder().url(url);
- for (String key : headers.keySet()) {
- requestBuilder.addHeader(key, headers.get(key));
- }
- Request request = requestBuilder.build();
- Response response = client.newCall(request).execute();
- InputStream inputStream;
- inputStream = response.body().byteStream();
- RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
- randomAccessFile.seek(0);
- byte[] buf = new byte[1024];
- int len;
- while ((len = inputStream.read(buf)) != -1) {
- randomAccessFile.write(buf, 0, len);
- }
- response.body().close();
- randomAccessFile.close();
- } catch (Exception ex) {
- ex.printStackTrace();
- System.err.println(ex);
- }
- }).start();
- }
最终使用,调用一下downloadFile,传入你在OSS中的文件名就好,下载好的文件会存到你的APP的downloads文件夹下:
最终请确认你的app开启了文件读写权限,以及网络访问权限:
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.INTERNET"/>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。