您的位置:首页 > 移动开发 > Android开发

Java4Android之APP自动升级

2014-09-11 11:13 405 查看
一个成熟的商业APP必须不断的退出新的版本。那么,不可能让用户自己去应用市场去下载新版本的应用,我们应该在应用内部提供自动升级的功能。自动升级其实包含两个层面,一个是整个APP的升级,也就是下载新版本的APP,然后安装替换掉现有的。还有一种升级是模块升级,这种升级一般采用静默升级,就是用户完全不知道。这个在我大迅雷里面经常做的,拿各个渠道去试错,对于一个互联网公司而言是再普通不过的了。而这些模块,肯定是诸如,解析库,下载库,播放库,这些后台库。。

不过今天,我要说的是APP的自动升级,模块的静默升级我们下次有时间再说。

APP升级流程

盗用别人的图,来说明一下升级APP的整体流程。



对,这个图是盗用别人的。因为,这就是APP升级的一般流程。
所以,我们知道了,第一步,我们需要去服务器查询版本信息,确定是不是要进行升级。

到服务器查询版本信息

具体见代码,
private static final class UpgradeLoader extends AsyncTask<Void, Void, UpdateInfo> {
private WeakReference<Activity> mContext;
private boolean mAuto;
private IUpgradeCheck mUpgradeCheckListener;
protected boolean mChecked;

public UpgradeLoader(Activity context, boolean auto, IUpgradeCheck listener) {
mContext = new WeakReference<Activity>(context);
mAuto = auto;
mUpgradeCheckListener = listener;
}

@Override
protected void onPreExecute() {
if (mUpgradeCheckListener != null) {
mUpgradeCheckListener.beforeCheck();
}
}

@Override
protected UpdateInfo doInBackground(Void... params) {
if (mUpgradeCheckListener != null) {
mUpgradeCheckListener.onCheck();
}
Context ctx = mContext.get();
String channel = "";
if (ctx != null) {
channel = Util.getChannelID(ctx);
}

return DataProxy.getInstance().getUpdateInfo(Util.getVersionName(MyApplication.sInstance),
Util.getOSVersion(), channel); //去服务器查询版本信息,这个是我们对http的一个封装,在这里,每个公司可以自己定义一些自己的地址和参数,非常简单的。
}

@Override
protected void onPostExecute(UpdateInfo result) {//从服务器查询回来,决定要不要升级
if (mUpgradeCheckListener != null) {
mUpgradeCheckListener.afterCheck();
}
if (!isCancelled()) {
if (result == null) {
if (!mAuto) {
UIHelper.showToast(MyApplication.sInstance, "检查更新失败", Toast.LENGTH_SHORT);
}
} else {
switch (result.type) {
case UpdateInfo.NO_UPGRADE:
if (!mAuto) {
UIHelper.showToast(KankanApplication.sInstance, "已经是最新版本,没有更新", Toast.LENGTH_SHORT);
}
break;

case UpdateInfo.UPDATE_NOT_TIPS:
if (!mAuto) {
buildDialog(result);
} else {
downloadApk(KankanApplication.sInstance, result.latestUrl);
}

break;
case UpdateInfo.UPDATE_TIPS:
case UpdateInfo.UPDATE_FOURCE:
if (!(mAuto && PreferenceManager.instance(mContext.get()).isVerionSkiped(result.latestVersion))) {
buildDialog(result);
}

default:
break;
}
}
}
}
注意上述代码。我们仅仅是示意,所以不可能把所有代码提供给大家学习。就是你第一步是去服务器查询版本信息。然后确定要下载APK的时候,则会调用downloadApk函数。对APK进行下载。

下载APK

在网上,很多人提供了采用httpclient去下载APK的方法,我这里给出另外一种思路。两种方法都可以,建议采用我们的提供的,因为,这个是针对下载较大文件的系统方法。

详见代码:
private static void downloadApk(Context context, String url) {
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(url);
String scheme = uri.getScheme();
if (scheme == null || (!scheme.equals("http") && !scheme.equals("https"))) {
LOG.error("only supports http/https url={}", url);
} else {
try {
DownloadManager.Request down = new DownloadManager.Request(uri);
down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
| DownloadManager.Request.NETWORK_WIFI);
down.setShowRunningNotification(true);
down.setVisibleInDownloadsUi(true);
down.setDestinationInExternalFilesDir(context, null, APK_NAME);
manager.enqueue(down);//开始下载
} catch (Exception e) {
e.printStackTrace();

UIHelper.showToast(context, "下载应用失败,请您去应用市场升级", Toast.LENGTH_LONG);
}
}
}
这样,使用DownloadManager可以非常方便的实现APK的下载。如果想对这个类进行更加深入的了解,大家可以去查询相关的资料。你可以查询下载进度等等相关的信息。

下载完成了,接下来就是要安装了。我们需要一个事件去触发安装。做法是,我们应该监听下载完成这件事情,下载完成之后,会有个广播发生,当监听到这个广播的时候我们就开始安装。

安装APK

监听下载完成,并安装。
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {//监听下载完成
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (id > -1) {
File file = queryFile(context, id);
if (file != null && file.exists()) {
Intent startInent = new Intent();
startInent.setAction(Intent.ACTION_VIEW);
startInent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startInent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
context.startActivity(startInent);//安装APK
}
}
}
}


至此,一个APK的自动升级就完成了。其实还有一些善后工作需要做的是,你需要删除APK,删除APK的方法应该是在安装完成之后删除,网上有说通过广播监听的方法来删除,就是监听到安装完成之后删除。这个大家去搜索一下就可以。

删除APK文件

这里,我还是给出点示例:
首先是要获取应用的安装状态,通过广播的形式

以下是和应用程序相关的Broadcast Action

ACTION_PACKAGE_ADDED 一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)

ACTION_PACKAGE_REPLACED 一个新版本的应用安装到设备,替换之前已经存在的版本

ACTION_PACKAGE_CHANGED 一个已存在的应用程序包已经改变,包括包名

ACTION_PACKAGE_REMOVED 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)

ACTION_PACKAGE_RESTARTED 用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)

ACTION_PACKAGE_DATA_CLEARED 用户已经清楚一个包的数据,包括包名(清除包程序不能接收到这个广播)

代码实现 

AndroidManifest.xml中定义广播

<receiver android:name=".AppInstallReceiver"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
然后是接收端:
public class AppInstallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
PackageManager manager = context.getPackageManager();
if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) {
String packageName = intent.getData().getSchemeSpecificPart();
Toast.makeText(context, "安装成功"+packageName, Toast.LENGTH_LONG).show();
}
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
String packageName = intent.getData().getSchemeSpecificPart();
Toast.makeText(context, "卸载成功"+packageName, Toast.LENGTH_LONG).show();
}
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {
String packageName = intent.getData().getSchemeSpecificPart();
Toast.makeText(context, "替换成功"+packageName, Toast.LENGTH_LONG).show();
<span style="white-space:pre">		</span>doanloadApk.delete();//从SD中删除刚刚下载的APK文件
}

}
}


好。APK自动升级就说道这里。

有时间,给大家说一下模块的静默升级的实现。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息