項目之前一直用的友盟的自動更新,但好像友盟那邊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;
}