2018/6/10 15:00:34当前位置推荐好文阿里云教程浏览文章

目前公司里的项目使用到的文件管理服务都是阿里云OSS,下面详情下Android端上传图片到阿里云OSS的具体实践。

阿里云OSS

1.阿里云OSS 移动应使用方案请见官方文档基于OSS的移动开发
2.阿里云OSS Android SDK的详情、安装、用请见官方文档

上传图片流程

  1. 从APP服务端获取Token
  2. 通过Token上传图片到阿里云OSS
  3. 成功后通知APP服务端。

简单图示如下(省略了APP服务端和阿里云OSS之间的交互流程)上传图片流程

代码实现

上面流程中实现了三次网络通信的操作,在实践中,用了RxJava的链式调使用,简洁、明了。

APP服务端的接口

  1. 请求Token的接口
  2. 通知APP服务端上传成功的接口
interface AppServiceApi {    // ...    @GET("aliyun/sts")    fun getAliOSSSTS(@Header("X-Authorization") token: String,                     @Query("right") right: String,                     @Query("prod") prod: String    ): Flowable<ApiResponse<AliOSSSTSModel>>    @PUT("users/v1/avatar")    fun notifyAvatarUpdate(@Header("X-Authorization") token: String    ): Flowable<ApiResponse<Boolean?>>    // ...}object AppService {    private val API_BASE_URL = BuildConfig.SERVICE_PLATFORM    fun api(): AppServiceApi {        val retrofit = Retrofit.Builder()                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())                .addConverterFactory(GsonConverterFactory.create())                .baseUrl(API_BASE_URL)                .build()        return retrofit.create(AppServiceApi::class.java)    }}

阿里云OSS的接口
上传图片的接口。其中将OSS SDK的方法改造成RxJava样式,便于链式调使用。

object AliOSSService {    private val clientConfiguration = config()    private fun config(): ClientConfiguration {        val conf = ClientConfiguration()        conf.connectionTimeout = 15  1000 // 连接超时,默认15秒        conf.socketTimeout = 15  1000 // socket超时,默认15秒        conf.maxConcurrentRequest = 5 // 最大并发请求数,默认5个        conf.maxErrorRetry = 2 // 失败后最大重试次数,默认2次        return conf    }    fun uploadFile(context: Context, stsModel: AliOSSSTSModel, fileData: ByteArray): Flowable<ApiResponse<Boolean?>> {        val credentialProvider = OSSStsTokenCredentialProvider(                stsModel.credentials.accessKeyId,                stsModel.credentials.accessKeySecret,                stsModel.credentials.securityToken)        val oss = OSSClient(context, stsModel.endpoint, credentialProvider, clientConfiguration)        val put = PutObjectRequest(stsModel.bucket, stsModel.objectKey, fileData)        return Flowable.create({ subscriber ->            oss.asyncPutObject(put, object : OSSCompletedCallback<PutObjectRequest, PutObjectResult> {                override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult?) {                    subscriber.onNext(ApiResponse(ApiCode.SUCCESS.code, true, "success"))                    subscriber.onComplete()                }                override fun onFailure(request: PutObjectRequest?, clientException: ClientException?, serviceException: ServiceException?) {                    subscriber.onError(ApiException(                            code = if (serviceException == null) "10" else serviceException.errorCode,                            message = serviceException?.rawMessage                    ))                }            })        }, BackpressureStrategy.LATEST)    }}

将三个接口封装成一个,便于调使用

object NetApi {   // avatar    fun uploadAvatar(context: Context, avatarData: ByteArray): Flowable<ApiResponse<Boolean?>> {        return AppService.api()                .getAliOSSSTS(token(),"WRITE", "OSS") // 获取Token                .flatMap { response ->                    AliOSSService.uploadFile(context, response.data!!, avatarData)                } // 上传图片                .subscribeOn(Schedulers.io())                .observeOn(Schedulers.io())                .flatMap {                    AppService.api().notifyAvatarUpdate(token()) // 通知服务端                }                .compose(apply()) // 线程切换等后续解决    }}

在上传图片的Activity中调使用接口就可

   private fun uploadAvatarWithToken(avatar: Drawable):Disposable {        val data = ImageUtils.drawable2Bytes(avatar, Bitmap.CompressFormat.PNG)        return NetApi.uploadAvatar(this, data)                .subscribe({                    Util.toast().showShort(R.string.avatar_upload_success_prompt)                    finish()                }, { t->                    if (!NetErrorHelper.handleAuth(t, this)) {                        Util.toast().showShort(R.string.avatar_upload_fail_prompt)                    }                })    }
网友评论