Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android開發學習之路-插件安裝、檢查應用是否安裝解決方案,android之路

Android開發學習之路-插件安裝、檢查應用是否安裝解決方案,android之路

編輯:關於android開發

Android開發學習之路-插件安裝、檢查應用是否安裝解決方案,android之路


使用Bmob的時候,如果需要用到支付功能,就需要讓應用去安裝一個支付插件。而一般的做法是將插件放置在assets目錄中,當用戶需要支付,先檢查是否能支付,不能的話,提示安裝插件。代碼:

 1 public class InstallHelper {
 2     private static final String TAG = "InstallHelper";
 3     private Context mContext;
 4 
 5     InstallHelper(Context context) {
 6         mContext = context;
 7     }
 8 
 9     void installAssetApk(String fileName) {
10         try {
11             InputStream is = this.mContext.getAssets().open(fileName);
12             File file = new File(mContext.getExternalCacheDir()+ File.separator +
13                     "demo.apk");
14             if (file.exists()) {
15                 file.delete();
16             }
17             file.createNewFile();
18             FileOutputStream fos = new FileOutputStream(file);
19             byte[] bytes = new byte[1024];
20             int i;
21             while ((i = is.read(bytes)) > 0) {
22                 fos.write(bytes, 0, i);
23             }
24             fos.close();
25             is.close();
26             Intent intent = new Intent(Intent.ACTION_VIEW);
27             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
28             intent.setDataAndType(Uri.parse("file://" + file), "application/vnd.android" + "" +
29                     ".package-archive");
30             mContext.startActivity(intent);
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34     }
35 }

我們不能直接執行assets下的安裝包,所以這裡的做法是先獲得Assets目錄的輸入流。接著創建一個文件,這個文件用來存放我們從assets目錄下讀出的安裝包內容。上述代碼中的12和13行中,我們通過getExternalCacheDir()來獲取主要存放的目錄,再通過File.separator來插入一個路徑分隔符,最後填上文件名來作為整個文件的絕對路徑。這裡有一個地方要說明,先看下面兩個方法:

getExternalCacheDir():獲取應用目錄下的cache目錄,不需要讀寫權限,應用刪除時也會刪除

getExternalStorageDirectory():獲取主外部儲存的根目錄,需要讀寫權限,應用刪除不會刪除

因為這個插件不需要共享給其他應用,所以我們需要使用第一個方法。如果使用了第二個,則會破壞掉用戶外部儲存的目錄結構,畢竟無端的多出了一個文件,用戶感覺當然是不好的。

接著判斷文件是否存在,若存在則重新建立。再創建一個byte數組來進行數據讀寫操作的輔助,不斷地從輸入流中讀入數據,寫到文件中。但是這裡有一個問題要注意,我們傳輸的是一個安裝包,只要最後傳輸的文件和assets目錄下的安裝包有一點不同,那麼這個安裝包都是不能使用的(安裝會提示解析出錯)。這裡要留意的地方就是22行,這個write方法不能寫錯。

如果我們直接使用:

fos.write(bytes); // 相當於fos.write(bytes, 0, bytes.length),也就是把整個bytes數組寫入輸出流

 則這個傳輸就不正確了,這裡先想想為什麼?可以看到,我們定義了一個局部變量i來獲取每次讀入的大小,只要這個i的值不為-1,則循環一直進行。但是試想最後一次循環的時候,假設數據只有500個byte,那麼我們直接調用fos.write(bytes)則是相當於把整一個bytes數組都寫進輸出流,但是實際上我們只需要前500個。

當讀寫完全後,我們可以通過Intent來打開這個安裝包,寫法就是上面那樣。


另一個內容就是檢查一個應用是否已經安裝,例如我們在調用微信分享的時候,如果用戶手機中沒有微信,那麼App將會沒任何反應,這不會是是我們希望看到的,所以一般會先判斷微信是否已經安裝(其他應用類似)。

判斷一個App是否已經安裝,我在StackOverFlow中看到的很多方法都是直接的使用PackageManager來獲取所有Activity對應的PackageInfo,代碼如下:

    private boolean isWechatInstall() {
        List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages
                (PackageManager.GET_ACTIVITIES);
        for (PackageInfo p : installedPackages) {
            if (p.packageName.equals("com.tencent.mm")) {
                return true;
            }
        }
        return false;
    }

 實際上這樣做是不行的。原因是系統中的應用Activity對應的Package是很多的,如果在短時間內對這些信息進行包裝,則會拋出異常並終止處理(一般處理30個左右就會自動終止),因為這個異常不是RuntimeException,所以我們的App也不會Crash掉,只是結果不正確。 

正確的做法應該是這樣:

    private boolean isAppInstalled(String packageName) {
        PackageManager pm = getPackageManager();
        boolean installed;
        try {
            pm.getPackageInfo(packageName, PackageManager
                    .GET_ACTIVITIES);
            installed = true;
        } catch (PackageManager.NameNotFoundException e) {
            installed = false;
        }
        return installed;
    }

直接根據包名獲取其PackageInfo對象,如果不存在,則在拋出的異常中返回false即可。 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved