抽取的Android自动更新库,目的是几行代码引入更新功能,含服务端代码,欢迎Star,欢迎Fork,谢谢~

目录

功能介绍

[x] 支持全量更新apk,直接升级到最新版本

[x] 支持增量更新,只下载补丁包升级

[x] 设置仅在wifi环境下更新

[x] 支持外部注入网络框架(库默认使用okhttp)

[x] 支持前台和后台自动更新

[x] 支持强制更新

[x] 支持对外定制更新提示和更新进度界面

[ ] 记忆下载

[x] 含发布功能后台服务端github (Node.js实现)

流程图

flowchart.jpg

效果图与示例apk

示例1

示例2

如何引入

Gradle引入

step 1

Add the JitPack repository to your build file

allprojects {

repositories {

...

maven { url 'https://jitpack.io' }

}

}

Step 2

Add the dependency

dependencies {

implementation 'com.github.itlwy:AppSmartUpdate:v1.0.6'

}

更新清单文件

该清单放置在静态服务器以供App访问,主要用于判断最新的版本,及要更新的版本资源信息等(示例见仓库根目录下的resources目录或直接访问后台代码 github),清单由服务端程序发布apk时生成,详见后台示例:github

{

"minVersion": 100, // app最低支持的版本代码(包含),低于此数值的app将强制更新

"minAllowPatchVersion": 100, // 最低支持的差分版本(包含),低于此数值的app将采取全量更新,否则采用差量

"newVersion": 101, // 当前最新版本代码

"tip": "test update", // 更新提示

"size": 1956631, // 最新apk文件大小

"apkURL": "https://raw.githubusercontent.com/itlwy/AppSmartUpdate/master/resources/app/smart-update.apk", // 最新apk 绝对url地址,也可用相对地址,如下方的"patchURL"字段

"hash": "ea97c8efa490a2eaf7d10b37e63dab0e", // 最新apk文件的md5值

"patchInfo": { // 差分包信息

"v100": { // v100表示-版本代码100的apk需要下载的差分包

"patchURL": "v100/100to101.patch", //差分包地址,相对此UpdateManifest.json文件的地址,也可用绝对地址

"tip": "101 version", // 提示

"hash": "ea97c8efa490a2eaf7d10b37e63dab0e", // 合成后apk(即版本代码101)的文件md5值

"size": 1114810 // 差分包大小

}

}

}

简单使用

1.初始化

public class MyApplication extends Application {

@Override

public void onCreate() {

super.onCreate();

//推荐在Application中初始化

Config config = new Config.Builder()

.isDebug(true)

.build(this);

UpdateManager.getInstance().init(config);

}

}

2.调用

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button mUpdateBtn;

private String manifestJsonUrl = "https://raw.githubusercontent.com/itlwy/AppSmartUpdate/master/resources/UpdateManifest.json";

private IUpdateCallback mCallback;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mUpdateBtn = (Button) findViewById(R.id.update_btn);

mUpdateBtn.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.update_btn:

UpdateManager.getInstance().update(this, manifestJsonUrl, null);

break;

}

}

}

详细说明

注册通知回调

其他activity界面需要获知后台更新情况

public void register(IUpdateCallback callback) {...}

public void unRegister(IUpdateCallback callback) {...}

public interface IUpdateCallback {

/**

* 通知无新版本需要更新,运行在主线程

*/

void noNewApp();

/**

* 自动更新准备开始时回调,运行在主线程,可做一些提示等

*/

void beforeUpdate();

/**

* 自动更新的进度回调(分增量和全量更新),运行在主线程

*

* @param percent 当前总进度百分比

* @param totalLength 更新总大小(全量为apk大小,增量为全部补丁大小和)

* @param patchIndex 当前更新的补丁索引(从1开始)

* @param patchCount 需要更新的总补丁数(当为0时表示是增量更新)

*/

void onProgress(int percent, long totalLength, int patchIndex, int patchCount);

/**

* 下载完成,准备更新,运行在主线程

*/

void onCompleted();

/**

* 异常回调,运行在主线程

*

* @param error 异常信息

*/

void onError(String error);

/**

* 用户取消了询问更新对话框

*/

void onCancelUpdate();

/**

* 取消了更新进度对话框,压入后台自动更新,此时由通知栏通知进度

*/

void onBackgroundTrigger();

}

网络框架注入

默认使用okhttp,也可由外部注入,只需实现如下的IHttpManager接口,然后通过new Config.Builder().httpManager(new OkhttpManager())注入即可

public interface IHttpManager {

IResponse syncGet(@NonNull String url, @NonNull Map params) throws IOException;

/**

* 异步get

*

* @param url get请求地址

* @param params get参数

* @param callBack 回调

*/

void asyncGet(@NonNull String url, @NonNull Map params, @NonNull Callback callBack);

/**

* 异步post

*

* @param url post请求地址

* @param params post请求参数

* @param callBack 回调

*/

void asyncPost(@NonNull String url, @NonNull Map params, @NonNull Callback callBack);

/**

* 下载

*

* @param url 下载地址

* @param path 文件保存路径

* @param fileName 文件名称

* @param callback 回调

*/

void download(@NonNull String url, @NonNull String path, @NonNull String fileName, @NonNull FileCallback callback);

}

定制更新交互界面

每个应用的风格都可能是不一样的,因此这里也支持自定义弹出的提示框和进度框,详细见如下代码示例:

初始化config时需要将内部默认的弹框屏蔽掉

public class MyApplication extends Application {

@Override

public void onCreate() {

super.onCreate();

Config config = new Config.Builder()

.isShowInternalDialog(false)

.build(this);

UpdateManager.getInstance().init(config);

}

}

自定义对话框,如下(详细代码在MainActivity.java里):

public void registerUpdateCallbak() {

mCallback = new IUpdateCallback() {

@Override

public void noNewApp() {

Toast.makeText(MainActivity.this, "当前已是最新版本!", Toast.LENGTH_LONG).show();

}

@Override

public void hasNewApp(AppUpdateModel appUpdateModel, UpdateManager updateManager, final int updateMethod) {

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

mDialog = builder.setTitle("自动更新提示")

.setMessage(appUpdateModel.getTip())

.setPositiveButton("更新", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

UpdateManager.getInstance().startUpdate(updateMethod);

}

})

.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

}

}).create();

mDialog.show();

}

@Override

public void beforeUpdate() {

// 更新开始

mProgressDialog = new ProgressDialog(MainActivity.this);

mProgressDialog.setTitle("更新中...");

mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

mProgressDialog.setMessage("正在玩命更新中...");

mProgressDialog.setMax(100);

mProgressDialog.setProgress(0);

mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

@Override

public void onCancel(DialogInterface dialog) {

// 退到后台自动更新,进度由通知栏显示

if (UpdateManager.getInstance().isRunning()) {

UpdateManager.getInstance().onBackgroundTrigger();

}

}

});

mProgressDialog.show();

}

@Override

public void onProgress(int percent, long totalLength, int patchIndex, int patchCount) {

String tip;

if (patchCount > 0) {

tip = String.format("正在下载补丁%d/%d", patchIndex, patchCount);

} else {

tip = "正在下载更新中...";

}

mProgressDialog.setProgress(percent);

mProgressDialog.setMessage(tip);

}

@Override

public void onCompleted() {

mProgressDialog.dismiss();

}

@Override

public void onError(String error) {

Toast.makeText(MainActivity.this, error, Toast.LENGTH_LONG).show();

mProgressDialog.dismiss();

}

@Override

public void onCancelUpdate() {

}

@Override

public void onBackgroundTrigger() {

Toast.makeText(MainActivity.this, "转为后台更新,进度由通知栏提示!", Toast.LENGTH_LONG).show();

}

};

UpdateManager.getInstance().register(mCallback);

}

差分包合成(jni)

​ 此部分采用的差分工具为开源bsdiff,用于生成.patch补丁文件,采用jni方式封装一个.so库供java调用,详见"smartupdate"库里的main/cpp目录源码,过程比较简单,就是写个jni的方法来直接调用bsdiff库,目录结构如下:

main

-cpp

-bzip2

-CMakeLists.txt

-patchUtils.c

-patchUtils.h

-update-lib.cpp

因为bsdiff还依赖了bzip2,所以这里涉及多个源文件编译链接问题,需要在CMakeLists.txt稍作修改:

# 将当前 "./src/main/cpp" 目录下的所有源文件保存到 "NATIVE_SRC" 中,然后在 add_library 方法调用。

aux_source_directory( . NATIVE_SRC )

# 将 "./src/main/cpp/bzip2" 目录下的子目录bzip2保存到 "BZIP2_BASE" 中,然后在 add_library 方法调用。

aux_source_directory( ./bzip2 BZIP2_BASE )

# 将 BZIP2_BASE 增加到 NATIVE_SRC 中,这样目录的源文件也加入了编译列表中,当然也可以不加到 NATIVE_SRC,直接调用add_library。

list(APPEND NATIVE_SRC ${BZIP2_BASE})

add_library( # Sets the name of the library.

update-lib

# Sets the library as a shared library.

SHARED

# Provides a relative path to your source file(s).

${NATIVE_SRC})

差分包生成

​ 服务端见github ,使用时将manifestJsonUrl改成部署的服务器地址即可,如下示例代码片段的注释处

public class MainActivity extends AppCompatActivity {

private String manifestJsonUrl = "https://raw.githubusercontent.com/itlwy/AppSmartUpdate/master/resources/UpdateManifest.json";

// private String manifestJsonUrl = "http://192.168.2.107:8000/app/UpdateManifest.json";

...

}

依赖

okhttp : com.squareup.okhttp3:okhttp:3.11.0

gson : com.google.code.gson:gson:2.8.0

android+后台自动更新+上架,Android增量自动更新相关推荐

  1. android 清理后自动重启,解决Android后台清理APP后,程序自动重启的问题

    最近解决了一个Android APP的bug,发现APP在被后台清理后,会自动重启.现象很奇怪,有的手机(HTC)后台清理后,程序必crash,而有的手机(小米)程序不会crash.查找问题时,发现H ...

  2. android 后台程序 设置 优先级,Android应用程序防止被LMK干掉

    引用 Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用.当系统觉得当前的资源非常有限的时候,为了保 证一些优先级高的程序能运行,就会 ...

  3. android后台自播放音乐,Android实现后台播放音乐(Service方式)

    Android实现后台播放音乐(Service方式) 实现: 在res文件夹下添加raw文件夹,添加mp3/4格式的音乐文件 注意命名规则只能是a-z,0-9,和下划线_ 不能大写字母和- Andro ...

  4. android 后台运行清理,【Android】App在后台被清理后的终极应对手段——重启应用...

    检测App是否在后台期间被销毁 添加一个null值的Object标记对象到Application,并在App运行期间赋值一个非null任意对象,如果App在后台期间被OS销毁,则该对象会被清空(适用于 ...

  5. android后台时不显示,Android后台下载问题

    下载任务显然需要在主线程之外处理. 而从当前执行下载任务的activity按了返回键,然后再次进入后,该activity已经被销毁并且重建了,并且一般情况下,在activity被销毁后,我们应该清理新 ...

  6. android 后台截屏代码,Android实现截图和分享功能的代码

    先给大家展示下效果图吧 直接上代码: xml的布局: android:id="@+id/btn_jp" android:layout_marginTop="10dip&q ...

  7. android更新软件,Android软件的自动更新

    今天重新写了一篇自动更新的文章,参考:http://aokunsang.iteye.com/blog/1750440.本篇文章的源码整理了下,上传到了附件,需要的去下载. 看了几个博客,讲自动升级的程 ...

  8. android自动更新demo,Android程序自动更新功能模块的实现方法【附完整demo源码下载】...

    本文实例讲述了Android程序自动更新功能模块的实现方法.分享给大家供大家参考,具体如下: 在程序启动的时候检测服务器上有没有对应版本更新,如果有更新,提示用户是否更新. 在程序启动的时候首先调用更 ...

  9. Android 8.0 蓝牙唤醒 Ble 锁屏 保活 后台 持续扫描 进程拉活 自动唤醒

    主要是api的说明,嫌啰嗦的可以直接看demo,demo中有个检测锁屏时间重复开启扫描的代码,主要是如果APP没有获得电量或者后台运行的权限,只能持续后台运行几小时. 这个demo的作用是实现8.0以 ...

最新文章

  1. Android开发中libs包下面的mips、armeabi、armeabi-v7a和x86
  2. 《Javascript高级程序设计》读书笔记之bind函数详解
  3. 防止电脑自动休眠小妙招
  4. xshell 6 连接debian系统拒绝了密码_原来连接Linux,还有这个方法
  5. 高效率测试之巧用策略模式 (引用)
  6. python爬虫框架scrapy操作步骤
  7. POJ 2299 Ultra-QuickSort(线段树+离散化)
  8. matlab小波分析
  9. SAP 后勤实施攻略笔记-生产模式和计划策略
  10. {工作记录}遇到过的网络攻击合集爬虫User-Agent记录..{持续更新}
  11. 新浪微博开放平台注册样例
  12. 解决XP系统每次关机都自动重启问题
  13. mysql 1556_mysqldump: Got error: 1556: You can't use locks with log tables.
  14. 搬砖(二分答案 + 线性规划)
  15. 深度学习笔记~感受野(receptive field)的计算
  16. Halcon 卡尺找圆
  17. 教你自动识别快递公司,过滤重复单号,查询物流信息
  18. S40手机上的来电防火墙
  19. 虚拟化——ovirt删除host主机操作步骤
  20. 四边形坐标顺时针排序

热门文章

  1. window自带的计算机应用程序,Win10系统电脑不小心将自带的应用程序卸载了该怎么恢复...
  2. 如何用深度学习进行语音识别
  3. canvas生成圆形图章(名称紧凑和散开)
  4. 用python画路飞代码_python 全栈开发,Day105(路飞其他数据库表结构,立即结算需求)...
  5. 计算机安全模式无法启动修复,win7系统崩溃无法修复和进入安全模式的解决方法...
  6. 与日历有关的小程序推荐
  7. Ubuntu 16.04 LTS安装XDM下载神器
  8. bufg和bufgp_Xilinx FPGA全局时钟和第二全局时钟资源的使用方法(转)
  9. 射频识别技术原理分析
  10. [GXYCTF2019]BabyUpload