為之于未有读处,治之于未亂尘分。
在Android開發(fā)中猜惋,軟件更新可以說是必不可少的,而隔壁的iOS喝著咖啡培愁,無情的嘲笑著這個他們不用再實現(xiàn)的功能著摔,因為蘋果會無情的拒絕所有包含軟件更新,哪怕是版本檢測的APP定续。作為苦逼的Android攻城獅谍咆,我們還是老老實實地研究一下如何實現(xiàn)軟件更新吧。
一私股、軟件升級的實現(xiàn)思路
-
下載APK
- 應用內(nèi)下載文件
應用內(nèi)實現(xiàn)文件下載摹察,如果退出程序,下載將結(jié)束倡鲸。 - Service下載文件
利用Service實現(xiàn)文件后臺下載供嚎,不受程序是否退出的影響。
- 應用內(nèi)下載文件
-
安裝APK
- 手動安裝
- 自動安裝
對于用戶而言,后臺下載并自動安裝必然是一個好的使用體驗克滴。使用Service去實現(xiàn)文件下載的話逼争,還需要我們自己維護網(wǎng)絡請求,這可是非常麻煩又頭痛的事情偿曙,有沒有一個更方便快捷的方式呢氮凝?下面將介紹一種簡單粗暴的實現(xiàn)方法!
二望忆、DownloadManager實現(xiàn)文件下載
- 使用DownloadManager實現(xiàn)APK下載
通過DownloadManager來實現(xiàn)文件下載罩阵,我們就可以完全不用考慮網(wǎng)絡請求、異步問題了启摄,系統(tǒng)幫我們處理了所有事情稿壁,你可以繼續(xù)操作App,即便是退出程序也不會影響APK的下載歉备。
/**
* 下載新版本
*
* @param context
* @param url
*/
public static void downLoadAPK(Context context, String url) {
if (TextUtils.isEmpty(url)) {
return;
}
try {
String serviceString = Context.DOWNLOAD_SERVICE;
final DownloadManager downloadManager = (DownloadManager) context.getSystemService(serviceString);
Uri uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(uri);
request.allowScanningByMediaScanner();
request.setVisibleInDownloadsUi(true);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setMimeType("application/vnd.android.package-archive");
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/juyoubang/","juyoubang.apk");
if (file.exists()){
file.delete();
}
request.setDestinationInExternalPublicDir(Environment.getExternalStorageDirectory().getAbsolutePath()+"/juyoubang/", "juyoubang.apk");
long refernece = downloadManager.enqueue(request);
SharePreHelper.getIns().setLongData("refernece", refernece);
} catch (Exception exception) {
ToastUtils.init(context).show("更新失敗");
}
}
三傅是、自動安裝
這里的自動安裝是指下載完成后,自動彈出安裝界面,而不是靜默安裝APK。同時這里不得不提的一個大坑就是Android6.0這個分水嶺候生,6.0以后的實現(xiàn)方式有所不同肠牲。
- 自定義Receiver接收系統(tǒng)廣播,實現(xiàn)軟件自動安裝迟隅。
Android6.0之前的版本我們可以通過Intent的方式來實現(xiàn),但是我們會發(fā)現(xiàn)6.0之后的手機上,下載完成后沒有任何效果浆劲,解決辦法就是通過打開文件的形式實現(xiàn)自動安裝。
public class UpdataBroadcastReceiver extends BroadcastReceiver {
@SuppressLint("NewApi")
public void onReceive(Context context, Intent intent) {
long myDwonloadID = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
long refernece = SharePreHelper.getIns().getLongData("refernece", 0);
if (refernece != myDwonloadID) {
return;
}
DownloadManager dManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Uri downloadFileUri = dManager.getUriForDownloadedFile(myDwonloadID);
installAPK(context,downloadFileUri);
}
private void installAPK(Context context,Uri apk ) {
if (Build.VERSION.SDK_INT < 23) {
Intent intents = new Intent();
intents.setAction("android.intent.action.VIEW");
intents.addCategory("android.intent.category.DEFAULT");
intents.setType("application/vnd.android.package-archive");
intents.setData(apk);
intents.setDataAndType(apk, "application/vnd.android.package-archive");
intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intents);
} else {
File file = queryDownloadedApk(context);
if (file.exists()) {
openFile(file, context);
}
}
}
/**
* 通過downLoadId查詢下載的apk哀澈,解決6.0以后安裝的問題
* @param context
* @return
*/
public static File queryDownloadedApk(Context context) {
File targetApkFile = null;
DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long downloadId = SharePreHelper.getIns().getLongData("refernece", -1);
if (downloadId != -1) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
Cursor cur = downloader.query(query);
if (cur != null) {
if (cur.moveToFirst()) {
String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
if (!TextUtils.isEmpty(uriString)) {
targetApkFile = new File(Uri.parse(uriString).getPath());
}
}
cur.close();
}
}
return targetApkFile;
}
private void openFile(File file, Context context) {
Intent intent = new Intent();
intent.addFlags(268435456);
intent.setAction("android.intent.action.VIEW");
String type = getMIMEType(file);
intent.setDataAndType(Uri.fromFile(file), type);
try {
context.startActivity(intent);
} catch (Exception var5) {
var5.printStackTrace();
Toast.makeText(context, "沒有找到打開此類文件的程序", Toast.LENGTH_SHORT).show();
}
}
private String getMIMEType(File var0) {
String var1 = "";
String var2 = var0.getName();
String var3 = var2.substring(var2.lastIndexOf(".") + 1, var2.length()).toLowerCase();
var1 = MimeTypeMap.getSingleton().getMimeTypeFromExtension(var3);
return var1;
}
}
- 最后記得在AndroidManifest.xml中注冊廣播
<receiver android:name=".receiver.UpdataBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
<!--<action android:name="android.intent.action.PACKAGE_INSTALL" />-->
</intent-filter>
</receiver>
- 還未實現(xiàn)功能:安裝成功后刪除apk文件牌借。
大功告成。
小插曲:當我把文件名稱"juyoubang.apk"寫成靜態(tài)常量來引用的時候割按,下載并安裝時膨报,會提示文件已損壞,無法安裝适荣,這讓我百思不得其解现柠。