標籤:java4android 自動升級 update downloadmanager
一個成熟的商業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自動升級就說道這裡。
有時間,給大家說一下模組的靜默升級的實現。
Java4Android之APP自動升級