diff --git a/README.md b/README.md
index 1877009..1aa0971 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
![Image](app/src/main/ic_launcher-web.png)
[![Download](https://img.shields.io/badge/download-App-blue.svg)](https://raw.githubusercontent.com/jenly1314/AppUpdater/master/app/release/app-release.apk)
-[![Jitpack](https://jitpack.io/v/jenly1314/AppUpdater.svg)](https://jitpack.io/#jenly1314/AppUpdater)
+[![JitPack](https://jitpack.io/v/jenly1314/AppUpdater.svg)](https://jitpack.io/#jenly1314/AppUpdater)
[![CI](https://travis-ci.org/jenly1314/AppUpdater.svg?branch=master)](https://travis-ci.org/jenly1314/AppUpdater)
[![CircleCI](https://circleci.com/gh/jenly1314/AppUpdater.svg?style=svg)](https://circleci.com/gh/jenly1314/AppUpdater)
[![API](https://img.shields.io/badge/API-15%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=15)
@@ -25,7 +25,8 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
- [x] 支持下载失败,重新下载
- [x] 支持下载优先取本地缓存
- [x] 支持通知栏提示内容和过程全部可配置
-- [x] 支持Android O
+- [x] 支持Android Q(10)
+- [x] 支持使用OkHttpClient下载
### [AndroidX version](https://github.com/jenly1314/AppUpdater/tree/androidx)
@@ -40,7 +41,7 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
com.king.app
app-updater
- 1.0.5
+ 1.0.6
pom
@@ -48,7 +49,7 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
com.king.app
app-dialog
- 1.0.5
+ 1.0.6
pom
```
@@ -57,25 +58,25 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
//----------AndroidX 版本
//app-updater
- implementation 'com.king.app:app-updater:1.0.5-androidx'
+ implementation 'com.king.app:app-updater:1.0.6-androidx'
//app-dialog
- implementation 'com.king.app:app-dialog:1.0.5-androidx'
+ implementation 'com.king.app:app-dialog:1.0.6-androidx'
- //----------Android 版本
+ //----------Android Support 版本
//app-updater
- implementation 'com.king.app:app-updater:1.0.5'
+ implementation 'com.king.app:app-updater:1.0.6'
//app-dialog
- implementation 'com.king.app:app-dialog:1.0.5'
+ implementation 'com.king.app:app-dialog:1.0.6'
```
### Lvy:
```lvy
//app-updater
-
+
//app-dialog
-
+
```
@@ -128,6 +129,7 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
.serUrl(mUrl)
.setFilename("AppUpdater.apk")
.build(getContext())
+ .setHttpManager(OkHttpManager.getInstance())//使用OkHttpClient实现下载,需依赖okhttp库
.start();
AppDialog.INSTANCE.dismissDialogFragment(getSupportFragmentManager());
}
@@ -140,6 +142,10 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
## 版本记录
+#### v1.0.6:2019-11-27
+* 新增OkHttpManager 如果使用了OkHttpManager则必须依赖[okhttp](https://github.com/square/okhttp)
+* 优化细节 (progress,total 变更 int -> long)
+
#### v1.0.5:2019-9-4
* 支持取消下载
diff --git a/app-dialog/src/main/java/com/king/app/dialog/AppDialog.java b/app-dialog/src/main/java/com/king/app/dialog/AppDialog.java
index b2f0e23..21e4cf0 100644
--- a/app-dialog/src/main/java/com/king/app/dialog/AppDialog.java
+++ b/app-dialog/src/main/java/com/king/app/dialog/AppDialog.java
@@ -234,8 +234,9 @@ public enum AppDialog {
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK && isCancel){
dismissDialog();
+ return true;
}
- return true;
+ return false;
}
});
diff --git a/app-updater/build.gradle b/app-updater/build.gradle
index 952d0f8..82b52fa 100644
--- a/app-updater/build.gradle
+++ b/app-updater/build.gradle
@@ -36,5 +36,6 @@ dependencies {
androidTestImplementation deps.test.espresso
//support
compileOnly deps.support.appcompat
+ compileOnly deps.okhttp
}
diff --git a/app-updater/src/main/java/com/king/app/updater/AppUpdater.java b/app-updater/src/main/java/com/king/app/updater/AppUpdater.java
index ab4a5e4..323e503 100644
--- a/app-updater/src/main/java/com/king/app/updater/AppUpdater.java
+++ b/app-updater/src/main/java/com/king/app/updater/AppUpdater.java
@@ -13,7 +13,9 @@ import android.util.Log;
import com.king.app.updater.callback.UpdateCallback;
import com.king.app.updater.constant.Constants;
+import com.king.app.updater.http.HttpManager;
import com.king.app.updater.http.IHttpManager;
+import com.king.app.updater.http.OkHttpManager;
import com.king.app.updater.service.DownloadService;
import com.king.app.updater.util.PermissionUtils;
@@ -54,11 +56,24 @@ public class AppUpdater {
mConfig.setUrl(url);
}
+ /**
+ * 设置下载更新进度回调
+ * @param callback
+ * @return
+ */
public AppUpdater setUpdateCallback(UpdateCallback callback){
this.mCallback = callback;
return this;
}
+ /**
+ * 设置一个IHttpManager
+ * @param httpManager AppUpdater内置提供{@link HttpManager} 和 {@link OkHttpManager}两种实现。
+ * 如果不设置,将默认使用{@link HttpManager},你也可以使用{@link OkHttpManager}或自己去实现一个
+ * {@link IHttpManager}。
+ * 当使用{@link OkHttpManager}时,必需依赖okhttp库
+ * @return
+ */
public AppUpdater setHttpManager(IHttpManager httpManager){
this.mHttpManager = httpManager;
return this;
@@ -71,10 +86,10 @@ public class AppUpdater {
if(mConfig!=null && !TextUtils.isEmpty(mConfig.getUrl())){
//如果mContext是Activity,则默认会校验一次动态权限。
if(mContext instanceof Activity){
- PermissionUtils.INSTANCE.verifyReadAndWritePermissions((Activity) mContext,Constants.RE_CODE_STORAGE_PERMISSION);
+ PermissionUtils.verifyReadAndWritePermissions((Activity) mContext,Constants.RE_CODE_STORAGE_PERMISSION);
}
- if(mConfig.isShowNotification() && !PermissionUtils.INSTANCE.isNotificationEnabled(mContext)){
+ if(mConfig.isShowNotification() && !PermissionUtils.isNotificationEnabled(mContext)){
Log.w(Constants.TAG,"Notification permission not enabled.");
}
@@ -128,7 +143,7 @@ public class AppUpdater {
}
/**
- * AppUpdater构建器
+ * AppUpdater建造者
*/
public static class Builder{
@@ -150,7 +165,7 @@ public class AppUpdater {
/**
* 设置保存的路径
- * @param path 下载保存的文件路径 (默认SD卡/.AppUpdater目录)
+ * @param path 下载保存的文件路径
* @return
*/
public Builder setPath(String path){
@@ -251,7 +266,7 @@ public class AppUpdater {
/**
* 设置FileProvider的authority
- * @param authority FileProvider的authority(默认兼容N,默认值context.getPackageName() + ".fileProvider")
+ * @param authority FileProvider的authority(默认兼容N,默认值{@link Context#getPackageName() + ".fileProvider"})
* @return
*/
public Builder setAuthority(String authority){
diff --git a/app-updater/src/main/java/com/king/app/updater/callback/UpdateCallback.java b/app-updater/src/main/java/com/king/app/updater/callback/UpdateCallback.java
index 818a892..e077cb3 100644
--- a/app-updater/src/main/java/com/king/app/updater/callback/UpdateCallback.java
+++ b/app-updater/src/main/java/com/king/app/updater/callback/UpdateCallback.java
@@ -24,7 +24,7 @@ public interface UpdateCallback {
* @param total
* @param isChange 进度百分比是否有改变,(主要可以用来过滤无用的刷新,从而降低刷新频率)
*/
- void onProgress(int progress,int total,boolean isChange);
+ void onProgress(long progress,long total,boolean isChange);
/**
* 完成
diff --git a/app-updater/src/main/java/com/king/app/updater/constant/Constants.java b/app-updater/src/main/java/com/king/app/updater/constant/Constants.java
index 047b66b..cd04af9 100644
--- a/app-updater/src/main/java/com/king/app/updater/constant/Constants.java
+++ b/app-updater/src/main/java/com/king/app/updater/constant/Constants.java
@@ -1,9 +1,5 @@
package com.king.app.updater.constant;
-import android.os.Environment;
-
-import java.io.File;
-
/**
* @author Jenly Jenly
*/
@@ -23,9 +19,12 @@ public final class Constants {
public static final String KEY_RE_DOWNLOAD = "app_update_re_download";
- public static final String DEFAULT_DIR_PATH = Environment.getExternalStorageDirectory() + File.separator + ".AppUpdater";
-
public static final int RE_CODE_STORAGE_PERMISSION = 0x66;
public static final int NONE = -1;
+
+ public static final String DEFAULT_FILE_PROVIDER = ".fileProvider";
+
+ public static final String DEFAULT_DIR = "apk";
+
}
diff --git a/app-updater/src/main/java/com/king/app/updater/http/HttpManager.java b/app-updater/src/main/java/com/king/app/updater/http/HttpManager.java
index 7251c87..10eb5c2 100644
--- a/app-updater/src/main/java/com/king/app/updater/http/HttpManager.java
+++ b/app-updater/src/main/java/com/king/app/updater/http/HttpManager.java
@@ -19,6 +19,7 @@ import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
/**
+ * HttpManager使用{@link HttpURLConnection}实现{@link IHttpManager}
* @author Jenly Jenly
*/
public class HttpManager implements IHttpManager {
@@ -29,12 +30,14 @@ public class HttpManager implements IHttpManager {
private boolean isCancel;
- private static HttpManager INSTANCE;
+ private static volatile HttpManager INSTANCE;
public static HttpManager getInstance(){
if(INSTANCE == null){
synchronized (HttpManager.class){
- INSTANCE = new HttpManager();
+ if(INSTANCE == null){
+ INSTANCE = new HttpManager();
+ }
}
}
@@ -45,6 +48,9 @@ public class HttpManager implements IHttpManager {
this(DEFAULT_TIME_OUT);
}
+ /**
+ * HttpManager对外暴露。如果没有特殊需求,推荐使用{@link HttpManager#getInstance()}
+ */
public HttpManager(int timeout){
this.mTimeout = timeout;
}
@@ -63,7 +69,7 @@ public class HttpManager implements IHttpManager {
/**
* 异步下载任务
*/
- private class DownloadTask extends AsyncTask {
+ private class DownloadTask extends AsyncTask {
private String url;
private String path;
@@ -111,15 +117,17 @@ public class HttpManager implements IHttpManager {
InputStream is = connect.getInputStream();
- int length = connect.getContentLength();
+ long length = connect.getContentLength();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- length = (int)connect.getContentLengthLong();
+ length = connect.getContentLengthLong();
}
- int progress = 0;
+ Log.d(Constants.TAG,"contentLength:" + length);
- byte[] buffer = new byte[4096];
+ long progress = 0;
+
+ byte[] buffer = new byte[8192];
int len;
File file = new File(path,filename);
@@ -132,7 +140,9 @@ public class HttpManager implements IHttpManager {
fos.write(buffer,0,len);
progress += len;
//更新进度
- publishProgress(progress,length);
+ if(length>0){
+ publishProgress(progress,length);
+ }
}
fos.flush();
@@ -176,7 +186,7 @@ public class HttpManager implements IHttpManager {
}
@Override
- protected void onProgressUpdate(Integer... values) {
+ protected void onProgressUpdate(Long... values) {
super.onProgressUpdate(values);
if(callback!=null){
if(!isCancelled()){
diff --git a/app-updater/src/main/java/com/king/app/updater/http/IHttpManager.java b/app-updater/src/main/java/com/king/app/updater/http/IHttpManager.java
index 8d8e724..a186522 100644
--- a/app-updater/src/main/java/com/king/app/updater/http/IHttpManager.java
+++ b/app-updater/src/main/java/com/king/app/updater/http/IHttpManager.java
@@ -7,6 +7,7 @@ import java.io.Serializable;
import java.util.Map;
/**
+ * IHttpManager 默认提供{@link HttpManager} 和 {@link OkHttpManager}两种实现。
* @author Jenly Jenly
*/
public interface IHttpManager {
@@ -39,7 +40,7 @@ public interface IHttpManager {
* @param progress
* @param total
*/
- void onProgress(int progress,int total);
+ void onProgress(long progress,long total);
/**
* 完成
diff --git a/app-updater/src/main/java/com/king/app/updater/http/OkHttpManager.java b/app-updater/src/main/java/com/king/app/updater/http/OkHttpManager.java
new file mode 100644
index 0000000..5347059
--- /dev/null
+++ b/app-updater/src/main/java/com/king/app/updater/http/OkHttpManager.java
@@ -0,0 +1,227 @@
+package com.king.app.updater.http;
+
+import android.os.AsyncTask;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import com.king.app.updater.constant.Constants;
+import com.king.app.updater.util.SSLSocketFactoryUtils;
+
+import org.apache.http.conn.ssl.SSLSocketFactory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.ConnectException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.Call;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * OkHttpManager使用{@link OkHttpClient}实现{@link IHttpManager}
+ * 使用OkHttpManager时必须依赖OkHttp库
+ * @author Jenly
+ */
+public class OkHttpManager implements IHttpManager {
+
+ private static final int DEFAULT_TIME_OUT = 20000;
+
+ private OkHttpClient okHttpClient;
+
+ private boolean isCancel;
+
+ private static volatile OkHttpManager INSTANCE;
+
+ public static OkHttpManager getInstance(){
+ if(INSTANCE == null){
+ synchronized (HttpManager.class){
+ if(INSTANCE == null){
+ INSTANCE = new OkHttpManager();
+ }
+ }
+ }
+
+ return INSTANCE;
+ }
+
+ private OkHttpManager(){
+ this(DEFAULT_TIME_OUT);
+ }
+
+ /**
+ * HttpManager对外暴露。如果没有特殊需求,推荐使用{@link HttpManager#getInstance()}
+ * @param timeout 超时时间,单位:毫秒
+ */
+ public OkHttpManager(int timeout){
+ this(new OkHttpClient.Builder()
+ .readTimeout(timeout, TimeUnit.MILLISECONDS)
+ .connectTimeout(timeout, TimeUnit.MILLISECONDS)
+ .sslSocketFactory(SSLSocketFactoryUtils.createSSLSocketFactory(),SSLSocketFactoryUtils.createTrustAllManager())
+ .hostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
+ .build());
+ }
+
+ /**
+ * HttpManager对外暴露,推荐使用{@link HttpManager#getInstance()}
+ * @param okHttpClient {@link OkHttpClient}
+ */
+ public OkHttpManager(@NonNull OkHttpClient okHttpClient){
+ this.okHttpClient = okHttpClient;
+ }
+
+
+ @Override
+ public void download(String url,final String path,final String filename, @Nullable Map requestProperty,final DownloadCallback callback) {
+ isCancel = false;
+ new DownloadTask(okHttpClient,url,path,filename,requestProperty,callback).execute();
+ }
+
+ @Override
+ public void cancel() {
+ isCancel = true;
+ }
+
+
+ /**
+ * 异步下载任务
+ */
+ private class DownloadTask extends AsyncTask {
+ private String url;
+
+ private String path;
+
+ private String filename;
+
+ private Map requestProperty;
+
+ private DownloadCallback callback;
+
+ private Exception exception;
+
+ private OkHttpClient okHttpClient;
+
+ public DownloadTask(OkHttpClient okHttpClient,String url, String path, String filename ,@Nullable Map requestProperty, DownloadCallback callback){
+ this.okHttpClient = okHttpClient;
+ this.url = url;
+ this.path = path;
+ this.filename = filename;
+ this.callback = callback;
+ this.requestProperty = requestProperty;
+
+ }
+
+ @Override
+ protected File doInBackground(Void... voids) {
+
+ try{
+ Request.Builder builder = new Request.Builder()
+ .url(url)
+ .addHeader("Accept-Encoding", "identity")
+ .get();
+
+ if(requestProperty!=null){
+ for(Map.Entry entry : requestProperty.entrySet()){
+ builder.addHeader(entry.getKey(),entry.getValue());
+ }
+ }
+
+ Call call = okHttpClient.newCall(builder.build());
+ Response response = call.execute();
+
+ if(response.isSuccessful()){
+ InputStream is = response.body().byteStream();
+
+ long length = response.body().contentLength();
+
+ Log.d(Constants.TAG,"contentLength:" + length);
+
+ long progress = 0;
+
+ byte[] buffer = new byte[8192];
+
+ int len;
+ File file = new File(path,filename);
+ FileOutputStream fos = new FileOutputStream(file);
+ while ((len = is.read(buffer)) != -1){
+ if(isCancel){
+ if(call != null){
+ call.cancel();
+ }
+ cancel(true);
+ break;
+ }
+ fos.write(buffer,0,len);
+ progress += len;
+ //更新进度
+ if(length>0){
+ publishProgress(progress,length);
+ }
+ }
+
+ fos.flush();
+ fos.close();
+ is.close();
+
+ response.close();
+
+ return file;
+
+ }else {//连接失败
+ throw new ConnectException(String.format("responseCode = %d",response.code()));
+ }
+
+ }catch (Exception e){
+ this.exception = e;
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if(callback!=null){
+ callback.onStart(url);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(File file) {
+ super.onPostExecute(file);
+ if(callback!=null){
+ if(file!=null){
+ callback.onFinish(file);
+ }else{
+ callback.onError(exception);
+ }
+
+ }
+ }
+
+ @Override
+ protected void onProgressUpdate(Long... values) {
+ super.onProgressUpdate(values);
+ if(callback!=null){
+ if(!isCancelled()){
+ callback.onProgress(values[0],values[1]);
+ }
+
+ }
+ }
+
+ @Override
+ protected void onCancelled() {
+ super.onCancelled();
+ if(callback!=null){
+ callback.onCancel();
+ }
+ }
+
+ }
+}
diff --git a/app-updater/src/main/java/com/king/app/updater/service/DownloadService.java b/app-updater/src/main/java/com/king/app/updater/service/DownloadService.java
index 1535c46..027c7f2 100644
--- a/app-updater/src/main/java/com/king/app/updater/service/DownloadService.java
+++ b/app-updater/src/main/java/com/king/app/updater/service/DownloadService.java
@@ -7,16 +7,14 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.net.Uri;
import android.os.Binder;
import android.os.Build;
-import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
-import android.support.v4.content.FileProvider;
+import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
@@ -118,16 +116,16 @@ public class DownloadService extends Service {
//如果保存路径为空则使用缓存路径
if(TextUtils.isEmpty(path)){
- path = getDiskCacheDir(getContext());
+ path = getExternalFilesDir(getContext());
}
File dirFile = new File(path);
if(!dirFile.exists()){
- dirFile.mkdir();
+ dirFile.mkdirs();
}
//如果文件名为空则使用路径
if(TextUtils.isEmpty(filename)){
- filename = AppUtils.INSTANCE.getAppFullName(getContext(),url,getResources().getString(R.string.app_name));
+ filename = AppUtils.getAppFullName(getContext(),url,getResources().getString(R.string.app_name));
}
mFile = new File(path,filename);
@@ -135,15 +133,15 @@ public class DownloadService extends Service {
Integer versionCode = config.getVersionCode();
if(versionCode!=null){
try{
- if(AppUtils.INSTANCE.apkExists(getContext(),versionCode,mFile)){
+ if(AppUtils.apkExists(getContext(),versionCode,mFile)){
//本地已经存在要下载的APK
Log.d(Constants.TAG,"CacheFile:" + mFile);
if(config.isInstallApk()){
String authority = config.getAuthority();
if(TextUtils.isEmpty(authority)){//如果为空则默认
- authority = getContext().getPackageName() + ".fileProvider";
+ authority = getContext().getPackageName() + Constants.DEFAULT_FILE_PROVIDER;
}
- AppUtils.INSTANCE.installApk(getContext(),mFile,authority);
+ AppUtils.installApk(getContext(),mFile,authority);
}
if(callback!=null){
callback.onFinish(mFile);
@@ -183,12 +181,13 @@ public class DownloadService extends Service {
* @param context
* @return
*/
- public String getDiskCacheDir(Context context) {
- if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
- return Constants.DEFAULT_DIR_PATH;
+ private String getExternalFilesDir(Context context) {
+ File[] files = ContextCompat.getExternalFilesDirs(context,Constants.DEFAULT_DIR);
+ if(files!=null && files.length > 0){
+ return files[0].getAbsolutePath();
}
+ return context.getExternalFilesDir(Constants.DEFAULT_DIR).getAbsolutePath();
- return context.getCacheDir().getAbsolutePath();
}
/**
@@ -237,8 +236,8 @@ public class DownloadService extends Service {
this.channelId = TextUtils.isEmpty(config.getChannelId()) ? Constants.DEFAULT_NOTIFICATION_CHANNEL_ID : config.getChannelId();
this.channelName = TextUtils.isEmpty(config.getChannelName()) ? Constants.DEFAULT_NOTIFICATION_CHANNEL_NAME : config.getChannelName();
}
- if(config.getNotificationIcon()<=0){
- this.notificationIcon = AppUtils.INSTANCE.getAppIcon(getContext());
+ if(config.getNotificationIcon() <=0 ){
+ this.notificationIcon = AppUtils.getAppIcon(getContext());
}else{
this.notificationIcon = config.getNotificationIcon();
}
@@ -247,7 +246,7 @@ public class DownloadService extends Service {
this.authority = config.getAuthority();
if(TextUtils.isEmpty(config.getAuthority())){//如果为空则默认
- authority = getContext().getPackageName() + ".fileProvider";
+ authority = getContext().getPackageName() + Constants.DEFAULT_FILE_PROVIDER;
}
this.isShowPercentage = config.isShowPercentage();
@@ -255,7 +254,6 @@ public class DownloadService extends Service {
}
-
@Override
public void onStart(String url) {
Log.d(Constants.TAG,"onStart:" + url);
@@ -271,7 +269,7 @@ public class DownloadService extends Service {
}
@Override
- public void onProgress(int progress, int total) {
+ public void onProgress(long progress, long total) {
boolean isChange = false;
long curTime = System.currentTimeMillis();
@@ -289,7 +287,7 @@ public class DownloadService extends Service {
content += percentage;
}
- showProgressNotification(notifyId, channelId, notificationIcon, getString(R.string.app_updater_progress_notification_title), content, progress, total);
+ showProgressNotification(notifyId, channelId, notificationIcon, getString(R.string.app_updater_progress_notification_title), content, currProgress, 100);
}
}
@@ -306,7 +304,7 @@ public class DownloadService extends Service {
isDownloading = false;
showFinishNotification(notifyId,channelId,notificationIcon,getString(R.string.app_updater_finish_notification_title),getString(R.string.app_updater_finish_notification_content),file,authority);
if(isInstallApk){
- AppUtils.INSTANCE.installApk(getContext(),file,authority);
+ AppUtils.installApk(getContext(),file,authority);
}
if(callback!=null){
callback.onFinish(file);
@@ -412,18 +410,7 @@ public class DownloadService extends Service {
cancelNotification(notifyId);
NotificationCompat.Builder builder = buildNotification(channelId,icon,title,content);
builder.setAutoCancel(true);
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- Uri uriData;
- String type = "application/vnd.android.package-archive";
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- uriData = FileProvider.getUriForFile(getContext(), authority, file);
- }else{
- uriData = Uri.fromFile(file);
- }
- intent.setDataAndType(uriData, type);
+ Intent intent = AppUtils.getInstallIntent(getContext(),file,authority);
PendingIntent clickIntent = PendingIntent.getActivity(getContext(), notifyId,intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(clickIntent);
Notification notification = builder.build();
@@ -468,7 +455,7 @@ public class DownloadService extends Service {
}
/**
- *
+ * 取消通知
* @param notifyId
*/
private void cancelNotification(int notifyId){
diff --git a/app-updater/src/main/java/com/king/app/updater/util/AppUtils.java b/app-updater/src/main/java/com/king/app/updater/util/AppUtils.java
index 5411ccf..8fa4be8 100644
--- a/app-updater/src/main/java/com/king/app/updater/util/AppUtils.java
+++ b/app-updater/src/main/java/com/king/app/updater/util/AppUtils.java
@@ -1,30 +1,36 @@
package com.king.app.updater.util;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
/**
* @author Jenly Jenly
*/
-public enum AppUtils {
+public final class AppUtils {
- INSTANCE;
+ private AppUtils(){
+ throw new AssertionError();
+ }
/**
* 通过url获取App的全名称
* @param context
* @return AppName.apk
*/
- public String getAppFullName(Context context,String url,String defaultName){
+ public static String getAppFullName(Context context,String url,String defaultName){
if(url.endsWith(".apk")){
return url.substring(url.lastIndexOf("/") + 1);
}
@@ -44,7 +50,7 @@ public enum AppUtils {
* @return
* @throws PackageManager.NameNotFoundException
*/
- public PackageInfo getPackageInfo(Context context) throws PackageManager.NameNotFoundException {
+ public static PackageInfo getPackageInfo(Context context) throws PackageManager.NameNotFoundException {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo( context.getPackageName(), 0);
return packageInfo;
@@ -66,7 +72,7 @@ public enum AppUtils {
/**
* 获取App的名称
*/
- public String getAppName(Context context) {
+ public static String getAppName(Context context) {
try{
int labelRes = getPackageInfo(context).applicationInfo.labelRes;
@@ -82,7 +88,7 @@ public enum AppUtils {
* @param context
* @return
*/
- public int getAppIcon(Context context){
+ public static int getAppIcon(Context context){
try{
return getPackageInfo(context).applicationInfo.icon;
} catch (Exception e) {
@@ -97,7 +103,19 @@ public enum AppUtils {
* @param context
* @param file
*/
- public void installApk(Context context,File file,String authority){
+ public static void installApk(Context context,File file,String authority){
+ Intent intent = getInstallIntent(context,file,authority);
+ context.startActivity(intent);
+ }
+
+ /**
+ * 获取安装Intent
+ * @param context
+ * @param file
+ * @param authority
+ * @return
+ */
+ public static Intent getInstallIntent(Context context,File file,String authority){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -111,7 +129,7 @@ public enum AppUtils {
uriData = Uri.fromFile(file);
}
intent.setDataAndType(uriData, type);
- context.startActivity(intent);
+ return intent;
}
/**
@@ -122,7 +140,7 @@ public enum AppUtils {
* @return
* @throws Exception
*/
- public boolean apkExists(Context context,int versionCode,File file) throws Exception{
+ public static boolean apkExists(Context context,int versionCode,File file) throws Exception{
if(file!=null && file.exists()){
String packageName = context.getPackageName();
PackageInfo packageInfo = AppUtils.getPackageInfo(context,file.getAbsolutePath());
@@ -135,4 +153,55 @@ public enum AppUtils {
}
return false;
}
+
+ /**
+ * 判断文件是否存在
+ * @param context
+ * @param path
+ * @return
+ */
+ public static boolean isAndroidQFileExists(Context context,String path){
+ return isAndroidQFileExists(context,new File(path));
+ }
+
+ /**
+ * 判断文件是否存在
+ * @param context
+ * @param file
+ * @return
+ */
+ public static boolean isAndroidQFileExists(Context context,File file){
+ AssetFileDescriptor descriptor = null;
+ ContentResolver contentResolver = context.getContentResolver();
+ try {
+ Uri uri = Uri.fromFile(file);
+ descriptor = contentResolver.openAssetFileDescriptor(uri, "r");
+ if (descriptor == null) {
+ return false;
+ } else {
+ close(descriptor);
+ }
+ return true;
+ } catch (FileNotFoundException e) {
+
+ }finally {
+ close(descriptor);
+ }
+ return false;
+ }
+
+ /**
+ * 关闭
+ * @param descriptor
+ */
+ private static void close(AssetFileDescriptor descriptor){
+ if(descriptor != null){
+ try {
+ descriptor.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
}
diff --git a/app-updater/src/main/java/com/king/app/updater/util/PermissionUtils.java b/app-updater/src/main/java/com/king/app/updater/util/PermissionUtils.java
index f6cd5b8..a4780a7 100644
--- a/app-updater/src/main/java/com/king/app/updater/util/PermissionUtils.java
+++ b/app-updater/src/main/java/com/king/app/updater/util/PermissionUtils.java
@@ -1,7 +1,6 @@
package com.king.app.updater.util;
import android.Manifest;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.NotificationManager;
@@ -18,22 +17,24 @@ import java.lang.reflect.Method;
/**
* @author Jenly Jenly
*/
-public enum PermissionUtils {
+public final class PermissionUtils {
- INSTANCE;
-
- private String[] PERMISSIONS_STORAGE = {
+ private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE};
+ private PermissionUtils(){
+ throw new AssertionError();
+ }
+
/**
* 校验权限
* @param activity
* @param requestCode
* @return
*/
- public boolean verifyReadAndWritePermissions(@NonNull Activity activity,int requestCode){
+ public static boolean verifyReadAndWritePermissions(@NonNull Activity activity,int requestCode){
int readResult = checkPermission(activity,Manifest.permission.READ_EXTERNAL_STORAGE);
int writeResult = checkPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE);
@@ -45,7 +46,7 @@ public enum PermissionUtils {
return true;
}
- public int checkPermission(@NonNull Activity activity,@NonNull String permission){
+ public static int checkPermission(@NonNull Activity activity,@NonNull String permission){
return ActivityCompat.checkSelfPermission(activity,permission);
}
@@ -53,7 +54,7 @@ public enum PermissionUtils {
* 获取通知权限
* @param context
*/
- public boolean isNotificationEnabled(Context context) {
+ public static boolean isNotificationEnabled(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/app-updater/src/main/java/com/king/app/updater/util/SSLSocketFactoryUtils.java b/app-updater/src/main/java/com/king/app/updater/util/SSLSocketFactoryUtils.java
index 5706cea..d337736 100644
--- a/app-updater/src/main/java/com/king/app/updater/util/SSLSocketFactoryUtils.java
+++ b/app-updater/src/main/java/com/king/app/updater/util/SSLSocketFactoryUtils.java
@@ -24,10 +24,10 @@ import javax.net.ssl.X509TrustManager;
/**
* @author Jenly Jenly
*/
-public class SSLSocketFactoryUtils {
+public final class SSLSocketFactoryUtils {
private SSLSocketFactoryUtils(){
-
+ throw new AssertionError();
}
public static SSLSocketFactory createSSLSocketFactory() {
diff --git a/app-updater/src/main/res/xml/app_updater_paths.xml b/app-updater/src/main/res/xml/app_updater_paths.xml
index bc154c1..0bf6011 100644
--- a/app-updater/src/main/res/xml/app_updater_paths.xml
+++ b/app-updater/src/main/res/xml/app_updater_paths.xml
@@ -2,10 +2,8 @@
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 414c9d9..2dc77d0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -30,6 +30,7 @@ dependencies {
//support
implementation deps.support.appcompat
implementation deps.support.constraintlayout
+ implementation deps.okhttp
implementation project(':app-updater')
implementation project(':app-dialog')
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
index f22eb05..739275e 100644
Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ
diff --git a/app/release/output.json b/app/release/output.json
index 670a4ef..ba0c81b 100644
--- a/app/release/output.json
+++ b/app/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":7,"versionName":"1.0.5","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":9,"versionName":"1.0.6","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/app/src/main/java/com/king/appupdater/MainActivity.java b/app/src/main/java/com/king/appupdater/MainActivity.java
index 8348b34..e15336d 100644
--- a/app/src/main/java/com/king/appupdater/MainActivity.java
+++ b/app/src/main/java/com/king/appupdater/MainActivity.java
@@ -3,7 +3,6 @@ package com.king.appupdater;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
@@ -20,6 +19,7 @@ import com.king.app.updater.UpdateConfig;
import com.king.app.updater.callback.AppUpdateCallback;
import com.king.app.updater.callback.UpdateCallback;
import com.king.app.updater.constant.Constants;
+import com.king.app.updater.http.OkHttpManager;
import com.king.app.updater.util.PermissionUtils;
import java.io.File;
@@ -42,8 +42,9 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.progressBar);
progressBar.setVisibility(View.INVISIBLE);
+ progressBar.setMax(100);
- PermissionUtils.INSTANCE.verifyReadAndWritePermissions(this,Constants.RE_CODE_STORAGE_PERMISSION);
+ PermissionUtils.verifyReadAndWritePermissions(this,Constants.RE_CODE_STORAGE_PERMISSION);
}
public Context getContext(){
@@ -78,6 +79,7 @@ public class MainActivity extends AppCompatActivity {
config.setUrl(mUrl);
config.addHeader("token","xxxxxx");
mAppUpdater = new AppUpdater(getContext(),config)
+ .setHttpManager(OkHttpManager.getInstance())
.setUpdateCallback(new UpdateCallback() {
@Override
@@ -94,10 +96,10 @@ public class MainActivity extends AppCompatActivity {
}
@Override
- public void onProgress(int progress, int total, boolean isChange) {
+ public void onProgress(long progress, long total, boolean isChange) {
if(isChange){
- progressBar.setMax(total);
- progressBar.setProgress(progress);
+ int currProgress = Math.round(progress * 1.0f / total * 100.0f);
+ progressBar.setProgress(currProgress);
}
}
@@ -134,7 +136,7 @@ public class MainActivity extends AppCompatActivity {
.build(getContext())
.setUpdateCallback(new AppUpdateCallback() {
@Override
- public void onProgress(int progress, int total, boolean isChange) {
+ public void onProgress(long progress, long total, boolean isChange) {
}
@@ -214,12 +216,13 @@ public class MainActivity extends AppCompatActivity {
public void onClick(View v) {
mAppUpdater = new AppUpdater.Builder()
.serUrl(mUrl)
- .setPath(Environment.getExternalStorageDirectory() + "/.AppUpdater")
+// .setPath(Environment.getExternalStorageDirectory() + "/.AppUpdater")//如果适配Android Q,则Environment.getExternalStorageDirectory()将废弃
+ .setPath(getExternalFilesDir(Constants.DEFAULT_DIR).getAbsolutePath())//自定义路径
.setVersionCode(BuildConfig.VERSION_CODE)//设置versionCode之后,新版本相同的apk只下载一次,优先取本地缓存。
- .setFilename("AppUpdater1.apk")
+ .setFilename("AppUpdater.apk")
.setVibrate(true)
.build(getContext());
- mAppUpdater.start();
+ mAppUpdater.setHttpManager(OkHttpManager.getInstance()).start();
AppDialog.INSTANCE.dismissDialog();
}
});
@@ -243,7 +246,7 @@ public class MainActivity extends AppCompatActivity {
.setVibrate(true)
.setSound(true)
.build(getContext());
- mAppUpdater.start();
+ mAppUpdater.setHttpManager(OkHttpManager.getInstance()).start();
AppDialog.INSTANCE.dismissDialogFragment(getSupportFragmentManager());
}
});
diff --git a/versions.gradle b/versions.gradle
index 956f90c..a0daf94 100644
--- a/versions.gradle
+++ b/versions.gradle
@@ -1,7 +1,7 @@
//App
def app_version = [:]
-app_version.versionCode = 7 //androidx 8
-app_version.versionName = "1.0.5"
+app_version.versionCode = 9 //androidx 10
+app_version.versionName = "1.0.6"
ext.app_version = app_version
//build version
@@ -22,6 +22,9 @@ versions.constraintLayout = "1.1.3"
versions.junit = "4.12"
versions.runner = "1.0.2"
versions.espresso = "3.0.2"
+
+versions.okhttp = "4.2.2"
+
ext.versions = versions
ext.deps = [:]
@@ -39,6 +42,9 @@ test.runner = "com.android.support.test:runner:$versions.runner"
test.espresso = "com.android.support.test.espresso:espresso-core:$versions.espresso"
deps.test = test
+//okHttp
+deps.okhttp = "com.squareup.okhttp3:okhttp:$versions.okhttp"
+
ext.deps = deps