开发过程中,发现很多更新库定制样式比较费事(如自定义dialog功能不完善,更新dialog和下载dialog耦合高等),且功能不是特别契合需求(如使用dialogfragment封装难修改圆角、样式较难定制),为加快开发速度提升效率,空闲时间简单封装了一个应用更新库和dialog库,独立于okhttp和retrofit。
项目地址:https://github.com/ibshe/AppUpdateLib
或:jackshen/AppUpdateLib
功能:
轻量、易用、可定制的android更新和dialog库,xml自定义ui,默认ios极简风格,一行代码实现更新提示和下载安装。支持静默更新,强制更新等,支持本地json和直接读取服务端json,一个builder定制化各种dialog,个性化toast。
效果图:
使用方式:
1、在你项目的根目录 build.gradle中加入如下配置:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
2、主app的build.gradle中添加依赖:
support版本:
github方式:
dependencies {
implementation 'com.github.ibshe:AppUpdateLib:1.0.7'
}
androidx版本:
dependencies {
implementation 'com.github.ibshe:AppUpdateLibX:1.0.7'
}
3、用法:
1. 一行代码检查更新、下载安装
new UpdateWrapper.Builder(this,mJsonUrl).build().start();
以上使用默认的更新dialog和下载dialog样式,以及默认toast提示,更多参数见下文。
也可自定义获取到服务端数据后解析成实体VersionModel传入,效果相同,优先级较高。
new UpdateWrapper.Builder(this,null)
.model(mModel)//本地实体,优先级 > url
.build()
.start();
2. 自定义更新dialog样式
布局文件完全自定义,布局内部元素在回调的view中自行处理,调用AbstractUpdateDialog的start()方法实现下载安装,调用cancel()取消更新等等,详见demo,下面举例:
custom_update_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/update_dialog_rootview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_gravity="center"
android:background="@drawable/update_bg_dark"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="260dp"
android:layout_centerInParent="true"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:layout_marginTop="10dp"
tools:text="@string/update_lib_dialog_title"
android:visibility="visible"
android:textColor="@color/dark_tx"
android:textStyle="bold"
android:textSize="20sp" />
<RelativeLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:paddingLeft="10dp"
android:paddingRight="10dp"
>
<TextView
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center|left"
android:layout_centerInParent="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:lineSpacingMultiplier="1.2"
android:textSize="16sp"
android:textColor="@color/dark_tx"
tools:text="@string/update_lib_update_content" />
</RelativeLayout>
<View
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginTop="10dp"
android:layout_below="@id/content"
android:background="@color/lineGray" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_below="@id/line">
<TextView
android:id="@+id/negtive"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:gravity="center"
android:singleLine="true"
tools:text="@string/update_lib_cancel"
android:textColor="@color/orange"
android:textSize="16sp" />
<View
android:id="@+id/column_line"
android:layout_width="1px"
android:layout_height="match_parent"
android:background="@color/lineGray" />
<TextView
android:id="@+id/positive"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:gravity="center"
android:singleLine="true"
tools:text="@string/update_lib_update"
android:textColor="@color/dark_tx"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
继承自AbstractUpdateDialog类的CustomDialog
class CustomDialog extends AbstractUpdateDialog {
public CustomDialog(Context context, final String title, final String negivteTx, final String positiveTx, int layoutId) {
super(context, title, negivteTx, positiveTx, layoutId, false, RadiusEnum.UPDATE_RADIUS_10, new DownlaodCallback() {
@Override
public void callback(int code, String message) {
Log.i(TAG,message);
}
});
this.customOnCreate(new BindingCallback() {
@Override
public void bindingVh(DialogViewHolder holder) {
View view = holder.getConvertView();
view.setBackgroundResource(ScreenUtils.getDrawableId(RadiusEnum.UPDATE_RADIUS_30.getType()));
titleTv = view.findViewById(R.id.title);
contentTv = view.findViewById(R.id.message);
negtive = view.findViewById(R.id.negtive);
positive = view.findViewById(R.id.positive);
titleTv.setText(title);
contentTv.setText(BaseConfig.UPDATE_CONTENT);
negtive.setText(negivteTx);
positive.setText(positiveTx);
negtive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
cancel();
}
});
positive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
start();
}
});
}
});
}
}
使用自定义更新dialog:
new UpdateWrapper.Builder(this,mJsonUrl)
.customDialog(new CustomDialog(this,"发现新版本","取消","升级",R.layout.custom_update_dialog))
.checkEveryday(false)
.radius(RadiusEnum.UPDATE_RADIUS_30)
.build()
.start();
xml完全自定义,例如:
3、静默下载(无notification,后台下载完成直接跳转安装)
new DownloadWrapper(this,mDownloadUrl,true,RadiusEnum.UPDATE_RADIUS_30).start();
4、强制更新
new UpdateWrapper.Builder(this,mJsonUrl)
.isMustUpdate(true)
.build()
.start();
5、设置下载dialog样式
new DownloadDialog.Builder(this,mDownloadUrl,false)
.downloadCallback(new DownlaodCallback() {
@Override
public void callback(int code, String message) {
}
})
.build()
.setDialogStyle(R.drawable.update_bg_dark)
.setCancelColor(R.color.orange)
.setConfirmColor(R.color.dark_tx)
.setTitleColor(R.color.dark_tx)
.setLineColor(R.color.lineGray)
.setProgressStyle(getResources().getDrawable(R.drawable.custom_progressbar_bg))
.start();
6、不弹或自定义更新dialog,下面方式调用直接下载
new DownloadWrapper(this,mDownloadUrl,false,RadiusEnum.UPDATE_RADIUS_10)
.start();
或者:
new DownloadDialog.Builder(this,mDownloadUrl,false)
.radius(RadiusEnum.UPDATE_RADIUS_10)
.build().start();
7、主要参数
new UpdateWrapper.Builder(this,mJsonUrl)
.title("测试更新")//更新dialog标题
.negtiveText("取消")//更新dialog取消按钮
.radius(RadiusEnum.UPDATE_RADIUS_10)//更新和下载dialog圆角弧度同时生效
.positiveText("立即升级")//更新dialog确定按钮
.checkEveryday(false)//默认false 立即下载,true 每天最多检查一次。如今日已检查,则不再检查
.showNetworkErrorToast(true)//无网络提示
.showNoUpdateToast(true)//无更新提示
.isPost(false)//检查更新请求协议是否为POST,默认GET
.isMustUpdate(false)//是否强制更新
.backgroundDownload(false)//是否后台下载
.model(null)//本地实体,不传默认为null,优先级大于mJsonUrl
.downloadCallback(new DownlaodCallback() {//下载状态回调
@Override
public void callback(int code, String message) {
//code 1、后台下载;2、取消下载;3、下载完成;4、下载失败;
//Code 1. Background download; 2. Cancel the download; 3. Download completed; 4. Download failed;
Log.i(TAG,message);
}
})
.updateCallback(new UpdateWrapper.UpdateCallback() {//获取远端信息回调
@Override
public void res(VersionModel model, boolean hasNewVersion) {
Log.i(TAG,model.toString());
}
})
.build()
.start();
8、当做dialog使用,自定义dialog样式,自定义toast都OK
new BsDialog(this, R.layout.custom_update_dialog) {
@Override
public void onBindViewHolder(DialogViewHolder holder) {
View view = holder.getConvertView();
titleTv = view.findViewById(com.boge.update.R.id.title);
contentTv = view.findViewById(com.boge.update.R.id.message);
negtive = view.findViewById(com.boge.update.R.id.negtive);
positive = view.findViewById(com.boge.update.R.id.positive);
titleTv.setText(TextUtils.isEmpty(mTitle)?(TextUtils.isEmpty(BaseConfig.UPDATE_TITLE)?mContext.getString(R.string.update_lib_dialog_title):BaseConfig.UPDATE_TITLE):mTitle);
contentTv.setText(BaseConfig.UPDATE_CONTENT);
negtive.setText(TextUtils.isEmpty(mNegivteTx)?(TextUtils.isEmpty(BaseConfig.UPDATE_NEGITIVE)?mContext.getString(R.string.update_no_thanks):BaseConfig.UPDATE_NEGITIVE):mNegivteTx);
positive.setText(TextUtils.isEmpty(mPositiveTx)?(TextUtils.isEmpty(BaseConfig.UPDATE_POSITIVE)?mContext.getString(R.string.update_sure):BaseConfig.UPDATE_POSITIVE):mPositiveTx);
if(mRadius.getType() != 10){
view.setBackgroundResource(ScreenUtils.getDrawableId(mRadius.getType()));
}
negtive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
cancel();
}
});
positive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
start();
}
});
}
}.backgroundLight(0.5)
.setCancelAble(true)
.setCanceledOnTouchOutside(true)
.showDialog();
9、服务端json格式(文件)
{
"versionCode":24,
"versionName":"1.7.8",
"content":"增加报表导出功能",
"minSupport":4,
"url":"http://103.45.138.168/apps/music_pj.apk",
"updateTitle":"发现新版本",
"mustUpdate":false,
"date":"2021-06-01 09:02:10"
}
10、代码混淆
-keep class com.boge.update.** {*;}
更多参数查看demo,欢迎提出问题或参与开源,ibshen@aliyun.com,如对你有帮助请star支持,谢谢
或 apk看效果