diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 3d3405e..2264837 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/misc.xml b/.idea/misc.xml index b0c7b20..e0d5b93 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -29,7 +29,7 @@ - + diff --git a/README.md b/README.md index 12da1ae..8371eaf 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版 - [x] 专注于App更新一键傻瓜式升级 - [x] 支持下载监听 - [x] 支持下载失败,重新下载 +- [x] 支持下载优先取本地缓存 - [x] 支持通知栏提示内容和过程全部可配置 - [x] 支持Android O @@ -38,7 +39,7 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版 com.king.app app-updater - 1.0.2 + 1.0.3 pom @@ -46,27 +47,27 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版 com.king.app app-dialog - 1.0.2 + 1.0.3 pom ``` ### Gradle: ```gradle //app-updater - implementation 'com.king.app:app-updater:1.0.2' + implementation 'com.king.app:app-updater:1.0.3' //app-dialog - implementation 'com.king.app:app-dialog:1.0.2' + implementation 'com.king.app:app-dialog:1.0.3' ``` ### Lvy: ```lvy //app-updater - + //app-dialog - + ``` @@ -130,11 +131,18 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版 更多使用示例请查看[App](app)。 ## 版本记录 + +#### v1.0.3:2019-5-9 +* 新增支持下载APK优先取本地缓存,避免多次下载相同版本的APK文件。 +* AppDialog支持隐藏Dialog的标题 + #### v1.0.2:2019-3-18 * 新增通知栏是否震动和铃声提示配置 -* AppDialogConfig新增getView(Context context)方法; -#### v1.0.2:2019-1-10 +* AppDialogConfig新增getView(Context context)方法 + +#### v1.0.1:2019-1-10 * 升级Gradle到4.6 + #### v1.0 :2018-6-29 * AppUpdater初始版本 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 c219152..a606b71 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 @@ -42,6 +42,7 @@ public enum AppDialog { View view = config.getView(context); TextView tvDialogTitle = view.findViewById(config.getTitleId()); setText(tvDialogTitle,config.getTitle()); + tvDialogTitle.setVisibility(config.isHideTitle() ? View.GONE : View.VISIBLE); TextView tvDialogContent = view.findViewById(config.getContentId()); setText(tvDialogContent,config.getContent()); @@ -56,7 +57,7 @@ public enum AppDialog { View line = view.findViewById(R.id.line); line.setVisibility(config.isHideCancel() ? View.GONE : View.VISIBLE); }catch (Exception e){ - e.printStackTrace(); + } Button btnDialogOK = view.findViewById(config.getOkId()); diff --git a/app-dialog/src/main/java/com/king/app/dialog/AppDialogConfig.java b/app-dialog/src/main/java/com/king/app/dialog/AppDialogConfig.java index 1ff8355..70acaa4 100644 --- a/app-dialog/src/main/java/com/king/app/dialog/AppDialogConfig.java +++ b/app-dialog/src/main/java/com/king/app/dialog/AppDialogConfig.java @@ -52,9 +52,13 @@ public class AppDialogConfig { */ private CharSequence ok; /** - * 是否隐藏取消按钮,如果取消则底部只显示一个按钮 + * 是否隐藏取消按钮,如果隐藏取消则底部只显示一个按钮 */ private boolean isHideCancel; + /** + * 是否隐藏标题 + */ + private boolean isHideTitle; private View.OnClickListener onClickCancel; @@ -161,6 +165,15 @@ public class AppDialogConfig { return this; } + public boolean isHideTitle(){ + return isHideTitle; + } + + public AppDialogConfig setHideTitle(boolean hideTitle){ + isHideTitle = hideTitle; + return this; + } + public View.OnClickListener getOnClickCancel() { return onClickCancel; } diff --git a/app-dialog/src/main/res/layout/app_dialog.xml b/app-dialog/src/main/res/layout/app_dialog.xml index f5d09a8..80f1634 100644 --- a/app-dialog/src/main/res/layout/app_dialog.xml +++ b/app-dialog/src/main/res/layout/app_dialog.xml @@ -24,7 +24,8 @@ android:padding="10dp" android:textSize="@dimen/app_dialog_content_text_size" android:textColor="@color/app_dialog_content_color" - android:layout_marginBottom="10dp" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" android:lineSpacingMultiplier="1" /> #FF4081 #333333 - #666666 + #333333 #333333 @color/colorAccent 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 a221bd5..6b64c29 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 @@ -79,7 +79,7 @@ public class AppUpdater { startDownloadService(); }else{ - throw new NullPointerException("url = null"); + throw new NullPointerException("Url = null"); } } @@ -263,6 +263,17 @@ public class AppUpdater { return this; } + /** + * 设置要下载APK的versionCode + * @param versionCode 为null表示不处理,默认不存在则下载,存在则重新下载。不为null时,表示会优先校验本地是否存在已下载版本号为versionCode的APK。 + * 如果存在则不会重新下载(AppUpdater会自动校验packageName一致性),直接取本地APK,反之重新下载。 + * @return + */ + public Builder setVersionCode(Integer versionCode) { + mConfig.setVersionCode(versionCode); + return this; + } + public AppUpdater build(@NonNull Context context){ AppUpdater appUpdater = new AppUpdater(context,mConfig); return appUpdater; diff --git a/app-updater/src/main/java/com/king/app/updater/UpdateConfig.java b/app-updater/src/main/java/com/king/app/updater/UpdateConfig.java index a756983..61d26f9 100644 --- a/app-updater/src/main/java/com/king/app/updater/UpdateConfig.java +++ b/app-updater/src/main/java/com/king/app/updater/UpdateConfig.java @@ -74,6 +74,11 @@ public class UpdateConfig implements Parcelable { */ private boolean isSound; + /** + * 要下载的APK的versionCode + */ + private Integer versionCode; + public UpdateConfig() { @@ -191,6 +196,14 @@ public class UpdateConfig implements Parcelable { isSound = sound; } + public Integer getVersionCode(){ + return versionCode; + } + + public void setVersionCode(Integer versionCode){ + this.versionCode = versionCode; + } + @Override public String toString() { return "UpdateConfig{" + @@ -208,6 +221,7 @@ public class UpdateConfig implements Parcelable { ", isShowPercentage=" + isShowPercentage + ", isVibrate=" + isVibrate + ", isSound=" + isSound + + ", versionCode=" + versionCode + '}'; } @@ -233,6 +247,7 @@ public class UpdateConfig implements Parcelable { dest.writeByte(this.isShowPercentage ? (byte) 1 : (byte) 0); dest.writeByte(this.isVibrate ? (byte) 1 : (byte) 0); dest.writeByte(this.isSound ? (byte) 1 : (byte) 0); + dest.writeValue(this.versionCode); } protected UpdateConfig(Parcel in) { @@ -250,6 +265,7 @@ public class UpdateConfig implements Parcelable { this.isShowPercentage = in.readByte() != 0; this.isVibrate = in.readByte() != 0; this.isSound = in.readByte() != 0; + this.versionCode = (Integer) in.readValue(Integer.class.getClassLoader()); } public static final Creator CREATOR = new Creator() { 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 abf649c..c70dc1e 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,6 +7,8 @@ import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -128,10 +130,34 @@ public class DownloadService extends Service { } File file = new File(path,filename); - if(file.exists()){ + if(file.exists()){//文件是否存在 + Integer versionCode = config.getVersionCode(); + if(versionCode!=null){ + try{ + if(AppUtils.INSTANCE.apkExists(getContext(),versionCode,file)){ + //本地已经存在要下载的APK + Log.d(Constants.TAG,"CacheFile:" + file); + if(config.isInstallApk()){ + String authority = config.getAuthority(); + if(TextUtils.isEmpty(authority)){//如果为空则默认 + authority = getContext().getPackageName() + ".fileProvider"; + } + AppUtils.INSTANCE.installApk(getContext(),file,authority); + } + if(callback!=null){ + callback.onFinish(file); + } + stopService(); + return; + } + }catch (Exception e){ + Log.w(Constants.TAG,e); + } + } + //删除旧文件 file.delete(); } - + Log.d(Constants.TAG,"File:" + file); if(httpManager != null){ httpManager.download(url,path,filename,new AppDownloadCallback(config,callback)); }else{ @@ -206,10 +232,10 @@ public class DownloadService extends Service { } this.isInstallApk = config.isInstallApk(); - if(TextUtils.isEmpty(config.getAuthority())){//如果为空默认 + + this.authority = config.getAuthority(); + if(TextUtils.isEmpty(config.getAuthority())){//如果为空则默认 authority = getContext().getPackageName() + ".fileProvider"; - }else{ - this.authority = config.getAuthority(); } this.isShowPercentage = config.isShowPercentage(); @@ -220,6 +246,7 @@ public class DownloadService extends Service { @Override public void onStart(String url) { + Log.d(Constants.TAG,"onStart:" + url); isDownloading = true; mLastProgress = 0; if(isShowNotification){ @@ -263,6 +290,7 @@ public class DownloadService extends Service { @Override public void onFinish(File file) { + Log.d(Constants.TAG,"onFinish:" + file); 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){ @@ -276,6 +304,7 @@ public class DownloadService extends Service { @Override public void onError(Exception e) { + Log.w(Constants.TAG,e); isDownloading = false; //支持下载失败重新并最多支持失败下载3次 boolean isReDownload = this.isReDownload && mCount < 3; @@ -293,6 +322,7 @@ public class DownloadService extends Service { @Override public void onCancel() { + Log.d(Constants.TAG,"onCancel"); isDownloading = false; cancelNotification(notifyId); if(callback!=null){ 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 7bb7959..bff377b 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 @@ -2,6 +2,7 @@ package com.king.app.updater.util; 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.net.Uri; @@ -19,7 +20,7 @@ public enum AppUtils { INSTANCE; /** - * + * 通过url获取App的全名称 * @param context * @return AppName.apk */ @@ -37,13 +38,30 @@ public enum AppUtils { return String.format("%s.apk",filename); } - + /** + * 获取包信息 + * @param context + * @return + * @throws PackageManager.NameNotFoundException + */ public PackageInfo getPackageInfo(Context context) throws PackageManager.NameNotFoundException { PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo( context.getPackageName(), 0); return packageInfo; } + /** + * 通过APK路径获取包信息 + * @param context + * @param archiveFilePath + * @return + */ + public static PackageInfo getPackageInfo(Context context, String archiveFilePath) throws Exception { + PackageManager packageManager = context.getPackageManager(); + PackageInfo packageInfo = packageManager.getPackageArchiveInfo(archiveFilePath, PackageManager.GET_ACTIVITIES); + return packageInfo; + } + /** * 获取App的名称 @@ -95,4 +113,26 @@ public enum AppUtils { intent.setDataAndType(uriData, type); context.startActivity(intent); } + + /** + * APK是否存在 + * @param context + * @param versionCode + * @param file + * @return + * @throws Exception + */ + public 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()); + if(packageInfo!=null && versionCode == packageInfo.versionCode){//比对versionCode + ApplicationInfo applicationInfo = packageInfo.applicationInfo; + if(applicationInfo!=null && packageName.equals(applicationInfo.packageName)){//比对packageName + return true; + } + } + } + return false; + } } 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 f1fcda4..d1d86b4 100644 --- a/app-updater/src/main/res/xml/app_updater_paths.xml +++ b/app-updater/src/main/res/xml/app_updater_paths.xml @@ -1,6 +1,10 @@ - - - + + + + + + + \ No newline at end of file diff --git a/app/release/app-release.apk b/app/release/app-release.apk index 3311109..b7e4451 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 1caf134..f72fe2b 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":3,"versionName":"1.0.2","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":4,"versionName":"1.0.3","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 2b2140b..501f784 100644 --- a/app/src/main/java/com/king/appupdater/MainActivity.java +++ b/app/src/main/java/com/king/appupdater/MainActivity.java @@ -1,12 +1,11 @@ package com.king.appupdater; -import android.app.Activity; 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.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; @@ -189,7 +188,7 @@ public class MainActivity extends AppCompatActivity { } /** - * 自定义弹框升级 + * 自定义弹框,优先缓存升级 */ private void clickBtn6(){ View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_custom,null); @@ -212,8 +211,9 @@ public class MainActivity extends AppCompatActivity { public void onClick(View v) { new AppUpdater.Builder() .serUrl(mUrl) - .setFilename(Environment.getExternalStorageDirectory() + "/.AppUpdater") - .setFilename("AppUpdater.apk") + .setPath(Environment.getExternalStorageDirectory() + "/.AppUpdater") + .setVersionCode(BuildConfig.VERSION_CODE)//设置versionCode之后,新版本相同的apk只下载一次,优先取本地缓存。 + .setFilename("AppUpdater1.apk") .setVibrate(true) .build(getContext()) .start(); @@ -245,6 +245,7 @@ public class MainActivity extends AppCompatActivity { } }); AppDialog.INSTANCE.showDialogFragment(getSupportFragmentManager(),config); + } public void OnClick(View v){ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index cb18606..5172e82 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -85,7 +85,7 @@ android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_marginTop="10dp" - android:text="自定义弹框升级" + android:text="自定义弹框,优先缓存升级" app:layout_constraintTop_toBottomOf="@+id/btn5" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" diff --git a/versions.gradle b/versions.gradle index 3218896..72b4e21 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,7 +1,7 @@ //App def app_version = [:] -app_version.versionCode = 3 -app_version.versionName = "1.0.2" +app_version.versionCode = 4 +app_version.versionName = "1.0.3" ext.app_version = app_version //build version