项目之前一直用的友盟的自动更新,但好像友盟那边10月份就开始不支持软件更新了,所以把更新的功能做到自己的服务器上面。
基本的实现思路如下:
1. 后台可以提供一个接口也可以,就是我们将当前的版本传过去,然后后台返回是否需要更新,如果需要,给出url,
2. 下载apk
3. 安装apk
具体实现:
1. 向服务器请求的结果如下
{
status: 1,
msg: "需要更新",
versionCode:1
updateUrl: "http://www.ejoooo.com/app/com.ejooo.jianli.apk"
}
后台已经帮我们判断了是否需要更新,我们只需要根据status的状态来判断是否做出进一步的操作。versionCode的作用是用来判断用户本地是否下载了最新的apk,避免重复下载。
2. 我是向后台请求数据后,弹出一个询问是否需要更新的对话框,点击确定操作后
Intent intent = new Intent(mContext.getApplicationContext(), DownLoadService.class);
intent.putExtra(UpdateConstants.FIELD_APK_DOWNLOAD_URL, VALUE_DOWNLOAD_URL);
intent.putExtra(UpdateConstants.FIELD_APK_NAME, appName);
intent.putExtra(UpdateConstants.FIELD_APK_PATH, mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath());
mContext.startService(intent);
3.这里需要注意的是
DownLoadService 不可集成IntentService,不然写在IntentService里面的BroadCastRecieve接收不到广播。
public class DownLoadService extends Service {
public static long DOWNLOAD_ID;
private String downloadUrl;
private String apkName;
private String apkPath;
/**
* 安卓系统下载类
**/
DownloadManager manager;
/**
* 接收下载完的广播
**/
DownloadCompleteReceiver receiver;
/**
* 初始化下载器
**/
private void initDownManager() {
manager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
receiver = new DownloadCompleteReceiver();
List<String> list = FileUtils.GetFiles(apkPath, "apk", apkName, false);
if (list.size() != 0) {
installAPK(Uri.fromFile(new File(list.get(0))));
return;
}
//设置下载地址
DownloadManager.Request down = new DownloadManager.Request(
Uri.parse(downloadUrl));
// 设置允许使用的网络类型,这里是移动网络和wifi都可以
down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
| DownloadManager.Request.NETWORK_WIFI);
// 下载时,通知栏显示途中
down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
// 显示下载界面
down.setVisibleInDownloadsUi(true);
// 设置下载后文件存放的位置
down.setDestinationInExternalFilesDir(this,
Environment.DIRECTORY_DOWNLOADS, apkName + ".apk");
// 将下载请求放入队列
DOWNLOAD_ID = manager.enqueue(down);
//注册下载广播
registerReceiver(receiver, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
downloadUrl = intent.getStringExtra(UpdateConstants.FIELD_APK_DOWNLOAD_URL);
apkName = intent.getStringExtra(UpdateConstants.FIELD_APK_NAME);
apkPath = intent.getStringExtra(UpdateConstants.FIELD_APK_PATH);
// 调用下载
initDownManager();
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
// 注销下载广播
if (receiver != null)
unregisterReceiver(receiver);
super.onDestroy();
}
/**
* 安装apk
* @param apk
*/
private void installAPK(Uri apk){
Intent intent = new Intent();
//执行动作
intent.setAction(Intent.ACTION_VIEW);
//执行的数据类型
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apk, "application/vnd.android.package-archive");
//不加下面这句话是可以的,查考的里面说如果不加上这句的话在apk安装完成之后点击单开会崩溃
//android.os.Process.killProcess(android.os.Process.myPid());
startActivity(intent);
}
// 接受下载完成后的intent
class DownloadCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//判断是否下载完成的广播
if (intent.getAction().equals(
DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
//获取下载的文件id
long downId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, -1);
//自动安装apk
installAPK(manager.getUriForDownloadedFile(downId));
//停止服务并关闭广播
DownLoadService.this.stopSelf();
}
}
/**
* 安装apk文件
*/
private void installAPK(Uri apk) {
// 通过Intent安装APK文件
Intent intent = new Intent();
//执行动作
intent.setAction(Intent.ACTION_VIEW);
//执行的数据类型
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apk, "application/vnd.android.package-archive");
//不加下面这句话是可以的,查考的里面说如果不加上这句的话在apk安装完成之后点击单开会崩溃
//android.os.Process.killProcess(android.os.Process.myPid());
startActivity(intent);
}
}
}
4.如何实现避免用户重复下载的问题
具体的实现方法是通过文件查找的方法,查找下载目录下面是否有最新的apk。至于apk是否为最新的,就需要在下载的时候通过versionName+versionCode命名,更新的时候从无夫妻获取到最新的versionCode 与文件名称做比较即可。
/**
* 查找文件
*
* @param Path 文件夹路径
* @param Extension 文件扩展名
* @param IsIterative 是否进入子文件夹
*/
public static List<String> GetFiles(String Path, String Extension, String fileName, boolean IsIterative) //搜索目录,扩展名,是否进入子文件夹
{
List<String> lstFile = new ArrayList<String>(); //结果 List
File[] files = new File(Path).listFiles();
if (files == null) {
return lstFile;
}
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
if (f.getPath().substring(f.getPath().length() - Extension.length()).equals(Extension)) { //判断扩展名
String name =files[i].getName();
if (files[i].getName().equals(fileName+".apk")) {
lstFile.add(f.getPath());
}
}
/*if (!IsIterative)
break;*/
} else if (f.isDirectory() && f.getPath().indexOf("/.") == -1) //忽略点文件(隐藏文件/文件夹)
GetFiles(f.getPath(), Extension, fileName, IsIterative);
}
return lstFile;
}