admin管理员组

文章数量:1532343

2023年12月14日发(作者:)

App的版本迭代更新

一、简介:

在APP开发中,应用上线后公司肯定后期会对应用进行维护对一些Bug修复,这种情况就需要版本迭代了。检测到服务器版本比本地手机版本高

的时候,手机会询问用户是否要下载最新的app,然后下载apk下来,然后进行安装。

备注:

也可以用第三方服务,比如腾讯的Bugly、Bmob云服务等,也挺方便的,不过apk要上传到第三方的平台上,如果公司要求在自己平台上,就只

能自己写了。

二、实现步骤

上一张开发中的版本迭代的流程图

具体来说大概是如下几步:

1、每次启动应用我们就获取放在服务器上的版本信息,我们获取到版本号与当前应用的版本好进行对比,这样我们就可以知道应用是否更新了,

版本信息一般包含如下内容:

{

"versionCode": "2", //版本号

"versionName": "2.0", //版本名称

//服务器上最新版本的app的下载地址

"apkUrl": "/",

"updateTitle": "更新提示" ,

"changeLog":"1.修复xxx Bug;2.更新了某某UI界面."

}

备注:

versionCode 2 //对用户不可见,仅用于应用市场、程序内部识别版本,判断新旧等用途。

versionName "2.0"//展示给用户,让用户会知道自己安装的当前版本.

//versionCode的值,必须是int

2、获取用户当前使用的APP的versionCode(版本号)

/**

* 获取当前APP版本号

* @param context

* @return

*/

public static int getPackageVersionCode(Context context){

PackageManager manager = kageManager();

PackageInfo packageInfo = null;

try {

packageInfo = kageInfo(kageName(),0);

} catch (tFoundException e) {

tackTrace();

}

if(packageInfo != null){

return nCode;

}else{

return 1;

}

}

3、拿到本地的版本号后,与获取到的服务器的最新的版本号做对比,如果比我们本地获取的APP的versionCode 高,则就进行下一步

//如果当前版本小于新版本,则更新

//获取当前app版本

int currVersionCode = kageVersionCode();

//newVersionCode自己通过网络框架访问服务器,解析数据得到

if(currVersionCode < newVersionCode){

Log.i("tag", "有新版本需要更新");

showHintDialog(); //弹出对话框,提示用户更新APP

}

4、如果服务器有新的高版本,则弹出对话框提示用户更新

//显示询问用户是否更新APP的dialog

private void showHintDialog() {

r builder = new r(this);

n(_launcher)

.setMessage("检测到当前有新版本,是否更新?")

.setNegativeButton("取消", new kListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//取消更新,则跳转到旧版本的APP的页面

xt(, "暂时不更新app", _SHORT).show();

}

})

.setPositiveButton("确定", new kListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//6.0以下系统,不需要请求权限,直接下载新版本的app

if (_INT < N_CODES.M) {

downloadApk();

} else {

//6.0以上,先检查,申请权限,再下载

checkPermission();

}

}

}).create().show();

}

5、如果用户选择了更新APP,则对手机系统版本进行判断

6.0以下系统,不需要请求权限,直接下载新版本的app

6.0以上,先检查,申请权限,再下载

顺便给出版本迭代需要的2个主要权限

<--网络权限-->

<--读写sdcard的权限-->

<--访问网络状态的权限-->

//检查权限

private void checkPermission() {

//app更新所需的权限

String[] permissions = {_EXTERNAL_STORAGE, ET};

if (missions(this, permissions)) {

// Already have permission, do the thing

// ...

downloadApk();

} else {

// Do not have permissions, request them now(请求权限)

tPermissions(this, "app更新需要读写sdcard的权限",

REQUEST_CODE_WRITE, permissions);

}

}

授权结果的回调:

//授权的结果的回调方法

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

estPermissionsResult(requestCode, permissions, grantResults);

if(requestCode == REQUEST_CODE_WRITE){

if( > 0 && grantResults[0] == SION_GRANTED){

downloadApk();

}

}

}

备注:

ET完全可以不用写,但是,我之前在比较复杂的测试中,遇到过问题,故此处就加上了。

权限申请,有时,用户拒绝了授权,并且勾选了不再提示的选项,那么用户会因为没有授权而不能使用一些功能,这样的用户体验是非常糟糕的,

为了解决这个问题,我们可以通过弹出自定义的Dialog来让用户打开APP设置界面去手动开启相应的权限,这样才能完整的使用app,所以还需要

实现sionCallbacks接口,重写如下方法

/**

* 用户同意授权了

*

* @param requestCode

* @param perms

*/

@Override

public void onPermissionsGranted(int requestCode, List perms) {

downloadApk();

Log.i("tag","--------->同意授权");

}

/**

* 用户拒绝了授权,则通过弹出对话框让用户打开app设置界面,

* 手动授权,然后返回app进行版本更新

*

* @param requestCode

* @param perms

*/

@Override

public void onPermissionsDenied(int requestCode, List perms) {

xt(this, "没有同意授权", _SHORT).show();

if (rmissionPermanentlyDenied(this, perms)) {

new r(this, "请设置权限")

.setTitle("设置对话框")

.setPositiveButton("设置")

.setNegativeButton("取消", null /* click listener */)

.setRequestCode(RC_SETTINGS_SCREEN)

.build()

.show();

}

}

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

vityResult(requestCode, resultCode, data);

if (requestCode == RC_SETTINGS_SCREEN) {

// Do something after user returned from app settings screen, like showing a Toast.

xt(this, "从app设置返回应用界面", _SHORT)

.show();

downloadApk();

}

}

----------------------至此我们也已经把下载APK的的权限也搞定了-----------------

7、接下来只需要进行下载安装即可,我们这时候就要判断,是否处于WiFi状态下,如果是WiFi情况下就直接进行更新,如果不是,再创建对话

框,然后询问用户,是否确定需要通过流量来进行下载:(因为一般下载都是在后台,所以都是放在Service中进行操作的。通过

startService(new Intent(, ));来启动服务进行下载)

判断是否处于WiFi状态

/**

* 判断是否处于WiFi状态

* getActiveNetworkInfo 是可用的网络,不一定是链接的,getNetworkInfo 是链接的。

*/

public static boolean isWifi(Context context) {

ConnectivityManager manager = (ConnectivityManager)context. getSystemService(CONNECTIVITY_SERVICE);

//NetworkInfo info = workInfo(_WIFI);

NetworkInfo networkInfo = iveNetworkInfo();

//处于WiFi连接状态

if (networkInfo != null && e() == _WIFI) {

return true;

}

return false;

}

新版app下载

//下载最新版的app

private void downloadApk() {

boolean isWifi = (this); //是否处于WiFi状态

if (isWifi) {

startService(new Intent(, ));

xt(, "开始下载。", _LONG).show();

} else {

//弹出对话框,提示是否用流量下载

r builder = new r(this);

le("提示");

sage("是否要用流量进行下载更新");

ativeButton("取消", new kListener() {

@Override

public void onClick(DialogInterface dialogInterface, int i) {

s();

xt(, "取消更新。", _LONG).show();

}

});

itiveButton("确定", new kListener() {

@Override

public void onClick(DialogInterface dialogInterface, int i) {

startService(new Intent(, ));

xt(, "开始下载。", _LONG).show();

}

});

celable(false);

AlertDialog dialog = ();

//设置不可取消对话框

celable(false);

celedOnTouchOutside(false);

();

}

}

备注:

如果对service不是很理解的童鞋,可以看看这篇文章深入理解Service

8、Service进行下载

这里是用DownloadManager进行下载的,下载完成后,点击通知的图标,可以自动安装。

这里顺便给出一个DownloadManager的链接,有需要的,可以自行阅读Android系统下载管理DownloadManager

1)通过DownLoadManager来进行APK的下载,代码如下:

//开始下载最新版本的apk文件

DownloadManager downloadManager = (DownloadManager)temService(DOWNLOAD_SERVICE);

//DownloadManager实现下载

t request = new t((_VERSION_APP_URL));

le("文件下载")

.setDestinationInExternalPublicDir(ORY_DOWNLOADS,_VERSION_APK_NAME)

//设置通知在下载中和下载完成都会显示

//.setNotificationVisibility(LITY_VISIBLE_NOTIFY_COMPLETED)

//设置通知只在下载过程中显示,下载完成后不再显示

.setNotificationVisibility(LITY_VISIBLE);

e(request);

2)下载完毕,自动安装的实现

当DownLoadManager下载完成后,会发送一个_DOWNLOAD_COMPLETE的广播,所以我们只要刚开始在启

动Service的时候,注册一个广播,监听

_DOWNLOAD_COMPLETE,然后当下载完成后,在BroadcastReceiver中调用安装APK的方法即可。

//广播接收的注册

public void receiverRegist() {

receiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

//安装apk

lApk(context);

stopSelf(); //停止下载的Service

}

};

IntentFilter filter = new IntentFilter(_DOWNLOAD_COMPLETE);

registerReceiver(receiver, filter); //注册广播

}

3)通过隐式意图安装apk

/**Apk的安装

*

* @param context

*/

public static void installApk(Context context) {

Intent intent = new Intent();

ion(_VIEW);

gs(_ACTIVITY_NEW_TASK); //这个必须有

aAndType(

le(new File(ernalStoragePublicDirectory(

ORY_DOWNLOADS), _VERSION_APK_NAME)),

"application/e-archive");

ctivity(intent);

}

Service中的完整代码

public class UpdateService extends Service {

public static final int NOTIFICATION_ID = 100;

private static final int REQUEST_CODE = 10; //PendingIntent中的请求码

//下载的新版本的apk的存放路径

public static final String destPath = ernalStoragePublicDirectory(ORY_DOWNLOADS) + tor + "";

private Context mContext = this;

private Notification mNotification;

private NotificationManager manager;

private r builder;

private RemoteViews remoteViews;

private BroadcastReceiver receiver;

@Nullable

@Override

public IBinder onBind(Intent intent) {

return null;

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

receiverRegist();

//下载apk文件

adApkByDownloadManager(this);

return _STICKY;

}

@Override

public void onDestroy() {

roy();

//解除注册

unregisterReceiver(receiver);

}

//广播接收的注册

public void receiverRegist() {

receiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

//安装apk

lApk(context);

stopSelf(); //停止下载的Service

}

};

IntentFilter filter = new IntentFilter(_DOWNLOAD_COMPLETE);

registerReceiver(receiver, filter); //注册广播

}

}

下面这段代码是自己封装的下载apk并实现自动安装的功能,如有不妥之处,敬请 指出

public class UpdateService extends IntentService {

public static final int NOTIFICATION_ID = 100;

private static final int REQUEST_CODE = 10; //PendingIntent中的请求码

public static final String destPath = ernalStoragePublicDirectory(ORY_DOWNLOADS) + tor + "";

private Context mContext = this;

private Notification mNotification;

private NotificationManager manager;

private r builder;

private RemoteViews remoteViews;

public UpdateService() {

super("UpdateService");

}

@Override

@Override

protected void onHandleIntent(Intent intent) {

if (intent != null) {

//开始下载最新版本的apk文件

initNotification();

download(_VERSION_APP_URL);

}

}

private void download(String newVersionApkUrl) {

BufferedInputStream bis = null;

BufferedOutputStream bos = null;

try {

URL url = new URL(newVersionApkUrl);

HttpURLConnection conn = (HttpURLConnection) nnection();

//设置连接的属性

nectTimeout(5000);

dTimeout(5000);

//如果响应码为200

if (ponseCode() == 200) {

bis = new BufferedInputStream(utStream());

bos = new BufferedOutputStream(new FileOutputStream(destPath));

int totalSize;

int count = 0; //读取到的字节数的计数器

int progress; //当前进度

byte[] data = new byte[1024 * 1024];

int len;

//文件总的大小

totalSize = tentLength();

while ((len = (data)) != -1) {

count += len; //读取当前总的字节数

(data, 0, len);

();

progress = (int) ((count / (float) totalSize) * 100);

//progress = (count * 100) / totalSize; //当前下载的进度

//重新设置自定义通知的进度条的进度

gressBar(ssBar, 100, progress, false);

tViewText(_progress, "已经下载了:" + progress + "%");

//发送通知

(NOTIFICATION_ID, mNotification);

}

}

} catch (IOException e) {

tackTrace();

} finally {

if (bis != null) {

try {

();

} catch (IOException e) {

tackTrace();

}

}

if (bos != null) {

try {

();

} catch (IOException e) {

tackTrace();

}

}

}

//下载文件完成以后,执行以下操作

Intent installIntent = new Intent();

/**启动系统服务的Activity,用于显示用户的数据。

比较通用,会根据用户的数据类型打开相应的Activity。

*/

ion(_VIEW);

aAndType(le(new File(destPath)), "application/e-archive");

//实例化延时的Activity

//实例化延时的Activity

PendingIntent pendingIntent = ivity(mContext, REQUEST_CODE, installIntent, _ONE_SHOT);

tentTitle("文件下载完毕!")

.setSmallIcon(_sys_download_done)

.setContentText("已下载100%")

.setContentIntent(pendingIntent);

//点击通知图标,自动消失

Notification notification = ();

|= _AUTO_CANCEL;

(NOTIFICATION_ID, notification);

}

//初始化通知

private void initNotification() {

builder = new r(mContext);

//自定义的Notification

remoteViews = new RemoteViews(getPackageName(), _main_notification);

Bitmap largeIcon = Resource(getResources(), _sys_download_anim0);

ker("开始下载apk文件")

.setSmallIcon(_sys_download_anim5)

.setLargeIcon(largeIcon)

.setContent(remoteViews);

//实例化通知对象

mNotification = ();

//获取通知的管理器

manager = (NotificationManager) getSystemService(CATION_SERVICE);

}

}

本文标签: 下载版本用户权限