提交 c976bf41 authored 作者: 祁增奎's avatar 祁增奎

1.Android增加OSS本地进行STS认证

2.增加配置参数以及方法
上级 68b1a2a9
## 0.0.1
## 1.0.0
* TODO: Describe initial release.
## 1.0.1
* MAINTENANCE: 增加外部控制,使用OSS模式还是普通模式
\ No newline at end of file
......@@ -6,6 +6,7 @@ import android.content.Intent
import android.util.Log
import androidx.annotation.NonNull
import com.clx.apk_update.DownloadAppUtil.aliDownload
import com.clx.apk_update.DownloadAppUtil.downloadApkWithoutSTS
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
......@@ -85,6 +86,36 @@ class ApkUpdatePlugin : FlutterPlugin, MethodCallHandler, EventChannel.StreamHan
}
"downloadApkWithoutSTS" -> {
val data = call.arguments<Map<String, String>>()
val ak = data?.get("ak")
val sk = data?.get("sk")
val endpoint = data?.get("endpoint")
val bucketName = data?.get("bucketName")
val objectKey = data?.get("objectKey")
val localPath = data?.get("localPath")
val localFileName = data?.get("localFileName")
if (ak == null || sk == null || endpoint == null || bucketName == null || objectKey == null || localPath == null || localFileName == null) {
result.error("error", "data is null", null)
return
}
Log.d(
"InstallAPKPlugin",
"setupMethodChannel: $ak $sk $endpoint $bucketName $objectKey $localPath"
)
downloadApkWithoutSTS(
mContext,
ak,
sk,
endpoint,
bucketName,
objectKey,
localPath,
localFileName,
this
)
}
else -> {
result.notImplemented()
}
......
......@@ -2,12 +2,14 @@ package com.clx.apk_update
import android.content.Context
import android.util.Log
import com.alibaba.sdk.android.oss.ClientConfiguration
import com.alibaba.sdk.android.oss.ClientException
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.ServiceException
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask
import com.alibaba.sdk.android.oss.model.ResumableDownloadRequest
......@@ -30,9 +32,33 @@ object DownloadAppUtil {
localFileName: String,
progressCallback: ProgressCallback
) {
downloadApkFile(context, OSSStsTokenCredentialProvider(ak, sk, token), endpoint, bucketName, objectKey, localPath, localFileName, progressCallback)
}
val credentialProvider: OSSCredentialProvider = OSSStsTokenCredentialProvider(ak, sk, token)
val oss = OSSClient(context, endpoint, credentialProvider)
fun downloadApkWithoutSTS(
context: Context,
ak: String,
sk: String,
endpoint: String,
bucketName: String,
objectKey: String,
localPath: String,
localFileName: String,
progressCallback: ProgressCallback
) {
// 使用AccessKey和SecretKey创建凭证提供者
downloadApkFile(context, OSSPlainTextAKSKCredentialProvider(ak, sk), endpoint, bucketName, objectKey, localPath, localFileName, progressCallback)
}
private fun downloadApkFile(context: Context,
provider: OSSCredentialProvider,
endpoint: String,
bucketName: String,
objectKey: String,
localPath: String,
localFileName: String,
progressCallback: ProgressCallback) {
val oss = OSSClient(context, endpoint, provider)
// 填写下载到本地文件所在的完整路径。
......@@ -77,9 +103,5 @@ object DownloadAppUtil {
Log.d(TAG, "aliDownload: task.isCompleted = ${task.isCompleted}")
}
}
\ No newline at end of file
......@@ -24,7 +24,7 @@ class MethodChannelApkUpdate extends ApkUpdatePlatform {
@override
void downloadApk(String ak, String sk, String token, String objectKey,
String endpoint, String bucketName, String localPath,localFileName) {
String endpoint, String bucketName, String localPath, localFileName) {
methodChannel.invokeMethod<String>('downloadInstall', {
"ak": ak,
"sk": sk,
......@@ -33,7 +33,27 @@ class MethodChannelApkUpdate extends ApkUpdatePlatform {
"endpoint": endpoint,
"bucketName": bucketName,
"localPath": localPath,
"localFileName":localFileName,
"localFileName": localFileName,
});
}
@override
void downloadApkWithoutSTS(
String ak,
String sk,
String objectKey,
String endpoint,
String bucketName,
String localPath,
String localFileName) {
methodChannel.invokeMethod<String>('downloadApkWithoutSTS', {
"ak": ak,
"sk": sk,
"objectKey": objectKey,
"endpoint": endpoint,
"bucketName": bucketName,
"localPath": localPath,
"localFileName": localFileName,
});
}
......
......@@ -32,11 +32,31 @@ abstract class ApkUpdatePlatform extends PlatformInterface {
}
//支持断点下载并安装
void downloadApk(String ak, String sk, String token, String objectKey,
String endpoint, String bucketName, String localPath,String localFileName) {
void downloadApk(
String ak,
String sk,
String token,
String objectKey,
String endpoint,
String bucketName,
String localPath,
String localFileName) {
throw UnimplementedError('downloadApk() has not been implemented.');
}
// 支持断点下载安装(不通过服务器验证STS)
void downloadApkWithoutSTS(
String ak,
String sk,
String objectKey,
String endpoint,
String bucketName,
String localPath,
String localFileName) {
throw UnimplementedError(
'downloadApkWithoutSTS() has not been implemented.');
}
// 添加下载进度监听
Stream<Map<String, Object>> addDownloadListener() {
throw UnimplementedError('addDownloadListener() has not been implemented.');
......
......@@ -12,20 +12,21 @@ class AppUpgradeFactory {
assert(config.token != null && config.token!.isNotEmpty, "请传递token参数");
assert(config.productCode != null, "请传递productCode参数");
DioUpdateUtil.dio.options.headers = {
...config.headers ?? {}
};
DioUpdateUtil.dio.options.headers = {...config.headers ?? {}};
// 配置版本服务
VersionService versionService = VersionServiceFactory.create(
config: config,
type: config.type ?? "pm",
);
// 配置下载服务
DownloadService downloadService = DownloadServiceFactory.create(
baseUrl: config.baseUrl,
token: config.token!,
productCode: config.productCode!,
);
DownloadService downloadService = config.needSTS == true
? DownloadServiceFactory.create(
baseUrl: config.baseUrl,
token: config.token!,
productCode: config.productCode!,
)
: DownloadServiceFactory.createWithoutToken(
baseUrl: config.baseUrl, productCode: config.productCode!);
return AppUpgradeControl(
versionService: versionService,
......
......@@ -32,6 +32,11 @@ class AppUpgradeConfig {
/// 顶部图片
final ImageProvider? topImageProvider;
/// 是否需要请求STS鉴权
final bool? needSTS;
@Deprecated(
'请使用AppUpgradeConfig.msl、AppUpgradeConfig.carrier、msl、AppUpgradeConfig.pm、AppUpgradeConfig.pmOSS代替')
const AppUpgradeConfig({
required this.baseUrl,
this.onceDay = false,
......@@ -43,5 +48,62 @@ class AppUpgradeConfig {
this.type,
this.headers,
this.topImageProvider,
this.needSTS = true,
});
/// 老马上来(建议走这个配置)
const AppUpgradeConfig.msl({
required this.baseUrl,
required this.productNo,
this.onceDay = false,
this.token,
this.productCode,
this.appleId,
this.versionNumber,
this.headers,
this.topImageProvider,
this.needSTS = true,
}) : type = 'msl';
/// 承运(建议走这个配置)
const AppUpgradeConfig.carrier({
required this.baseUrl,
this.onceDay = false,
this.token,
this.productCode,
this.appleId,
this.versionNumber,
this.headers,
this.topImageProvider,
this.needSTS = true,
}) : type = 'carrier',
productNo = null;
/// 项目管理工具(自动配置走OSS还是普通下载,需要Token鉴权)
const AppUpgradeConfig.pm({
required this.baseUrl,
this.onceDay = false,
this.token,
this.productCode,
this.appleId,
this.versionNumber,
this.headers,
this.topImageProvider,
}) : type = 'pm',
productNo = null,
needSTS = true;
/// 项目管理工具(自动配置走OSS还是普通下载,不需要Token鉴权)
const AppUpgradeConfig.pmOSS({
required this.baseUrl,
this.onceDay = false,
this.productCode,
this.appleId,
this.versionNumber,
this.headers,
this.topImageProvider,
}) : type = 'pm',
token = '此Token无效,只为了兼容',
productNo = null,
needSTS = false;
}
......@@ -18,4 +18,16 @@ class DownloadServiceFactory {
return NormalDownloadImpl();
}
}
static DownloadService createWithoutToken({
required String baseUrl,
required String productCode,
}) {
if (baseUrl.startsWith("https://gateway.")) {
return OSSDownloadImpl.withoutToken(
baseUrl: baseUrl, productCode: productCode);
} else {
return NormalDownloadImpl();
}
}
}
......@@ -17,13 +17,20 @@ class OSSDownloadImpl implements DownloadService {
final String baseUrl;
final String token;
final String productCode;
final bool needSTS;
StreamSubscription<Map<String, Object>>? _subscription;
OSSDownloadImpl({
required this.baseUrl,
required this.token,
required this.productCode,
});
}) : needSTS = true;
OSSDownloadImpl.withoutToken({
required this.baseUrl,
required this.productCode,
}) : token = "",
needSTS = false;
@override
Future<void> download({
......@@ -47,17 +54,7 @@ class OSSDownloadImpl implements DownloadService {
}
// 删除历史下载文件
await deleteFiles(Directory(path));
var ossInfo = await getOssInfo();
if (ossInfo == null) {
onError?.call(Exception("oss信息获取失败,请稍后重新"));
return;
}
// 使用OSS下载
var ak = ossInfo?['onceAccessKeyId'];
var sk = ossInfo?["onceAccessKeySecret"];
var token = ossInfo?["onceSecurityToken"];
var objectKey = getObjectKey(url);
var localPathFileName = getFileName(objectKey);
_subscription =
ApkUpdatePlatform.instance.addDownloadListener().listen((event) {
var count = event['currentSize'] as num;
......@@ -78,15 +75,36 @@ class OSSDownloadImpl implements DownloadService {
onProgress?.call(progress); // 下载进度
});
ApkUpdatePlatform.instance.downloadApk(
ak,
sk,
token,
objectKey,
Constants.ossEndpoint,
getOssBucketName(),
path,
localPathFileName);
final objectKey = getObjectKey(url);
if (needSTS) {
var ossInfo = await getOssInfo();
if (ossInfo == null) {
onError?.call(Exception("oss信息获取失败,请稍后重新"));
return;
}
// 使用OSS下载
var ak = ossInfo?['onceAccessKeyId'];
var sk = ossInfo?["onceAccessKeySecret"];
var token = ossInfo?["onceSecurityToken"];
ApkUpdatePlatform.instance.downloadApk(
ak,
sk,
token,
objectKey,
Constants.ossEndpoint,
getOssBucketName(),
path,
getFileName(objectKey));
} else {
ApkUpdatePlatform.instance.downloadApkWithoutSTS(
'LTAI5t9tqPPGM2g8YE8g899t',
'ENGYeR4r5TQdeYz7C51KBsrwE89g7d',
objectKey,
Constants.ossEndpoint,
getOssBucketName(),
path,
getFileName(objectKey));
}
} catch (e) {
debugPrint(e.toString());
onError?.call(Exception(e.toString()));
......
name: apk_update
description: A new Flutter project.
version: 1.0.0
version: 1.0.1
homepage:
environment:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论