支持下载APK优先取本地缓存,避免多次下载相同版本的APK

android
jenly1314 6 years ago
parent 5d8913439c
commit 4798dca4e7
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 2
      .idea/misc.xml
  3. 24
      README.md
  4. 3
      app-dialog/src/main/java/com/king/app/dialog/AppDialog.java
  5. 15
      app-dialog/src/main/java/com/king/app/dialog/AppDialogConfig.java
  6. 3
      app-dialog/src/main/res/layout/app_dialog.xml
  7. 2
      app-dialog/src/main/res/values/colors.xml
  8. 13
      app-updater/src/main/java/com/king/app/updater/AppUpdater.java
  9. 16
      app-updater/src/main/java/com/king/app/updater/UpdateConfig.java
  10. 40
      app-updater/src/main/java/com/king/app/updater/service/DownloadService.java
  11. 44
      app-updater/src/main/java/com/king/app/updater/util/AppUtils.java
  12. 10
      app-updater/src/main/res/xml/app_updater_paths.xml
  13. BIN
      app/release/app-release.apk
  14. 2
      app/release/output.json
  15. 11
      app/src/main/java/com/king/appupdater/MainActivity.java
  16. 2
      app/src/main/res/layout/activity_main.xml
  17. 4
      versions.gradle

@ -29,7 +29,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

@ -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版
<dependency>
<groupId>com.king.app</groupId>
<artifactId>app-updater</artifactId>
<version>1.0.2</version>
<version>1.0.3</version>
<type>pom</type>
</dependency>
@ -46,27 +47,27 @@ AppUpdater for Android 是一个专注于App更新,一键傻瓜式集成App版
<dependency>
<groupId>com.king.app</groupId>
<artifactId>app-dialog</artifactId>
<version>1.0.2</version>
<version>1.0.3</version>
<type>pom</type>
</dependency>
```
### 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
<dependency org='com.king.app' name='app-dialog' rev='1.0.2'>
<dependency org='com.king.app' name='app-dialog' rev='1.0.3'>
<artifact name='$AID' ext='pom'></artifact>
</dependency>
//app-dialog
<dependency org='com.king.app' name='app-dialog' rev='1.0.2'>
<dependency org='com.king.app' name='app-dialog' rev='1.0.3'>
<artifact name='$AID' ext='pom'></artifact>
</dependency>
```
@ -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初始版本

@ -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());

@ -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;
}

@ -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" />
<include layout="@layout/app_dialog_line_h"/>
<LinearLayout

@ -4,7 +4,7 @@
<color name="colorAccent">#FF4081</color>
<color name="app_dialog_title_color">#333333</color>
<color name="app_dialog_content_color">#666666</color>
<color name="app_dialog_content_color">#333333</color>
<color name="app_dialog_button_normal_color">#333333</color>
<color name="app_dialog_button_pressed_color">@color/colorAccent</color>

@ -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;

@ -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<UpdateConfig> CREATOR = new Creator<UpdateConfig>() {

@ -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())){//如果为空默认
authority = getContext().getPackageName() + ".fileProvider";
}else{
this.authority = config.getAuthority();
if(TextUtils.isEmpty(config.getAuthority())){//如果为空则默认
authority = getContext().getPackageName() + ".fileProvider";
}
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){

@ -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;
}
}

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="root_path" path="."/>
<external-path name="app_updater_path" path=".AppUpdater"/>
<cache-path name="data_path" path="data/data"/>
<external-path name="app_external_path" path="."/>
<external-path name="app_updater_path" path=".AppUpdater/"/>
<external-cache-path name="app_external_cache_path" path="."/>
<external-files-path name="app_external_files_path" path="."/>
<files-path name="app_files_path" path="."/>
<cache-path name="app_cache_path" path="."/>
</paths>

Binary file not shown.

@ -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":{}}]
[{"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":{}}]

@ -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){

@ -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"

@ -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

Loading…
Cancel
Save