關於 Android Obb 檔案的掛載, 筆者提供兩個方式 (2 擇 1, alternative) 對於 Obb 檔案進行掛載 . 讀者有興趣的話可以挑一個方式實驗. 這第2個方法是筆者所發現 (發明???) 的. 原理也很簡單, 就是開一個新的執行緒觀察 (Monitoring) "Obb" 這個資料夾. 當 onObb() 被呼叫時即是 Obb 檔案掛載成功. 值得注意的是: Obb 檔案掛載成功後, 即使是 App 退出, 也千萬不要將其卸載.
方法1:
方法1 使用 OnObbStateChangeListener, 因此我們 new 一個 OnObbStateChangeListener(), 但我們 overload 它的 onObbStateChange() 方法. 在 onObbStateChange() 過濾錯誤的 state . MountObb1() 最後呼叫 StorageManager 之 mountObb() .
...
DATA_PATH = SM.getMountedObbPath(Path);
...
DATA_PATH 就是我們所要的. Example 如下:
...
private Handler mObbHandler = null;
private OnObbStateChangeListener mObbStateHandler = null;
private ProgressDialog mLoadingDlg = null;
...
private void MountObb1(final String OBBPath) {
final StorageManager SM = (StorageManager) getSystemService(STORAGE_SERVICE);
mLoadingDlg = new ProgressDialog(this);
mLoadingDlg.setCancelable(true);
mLoadingDlg.setMessage(getString(R.string.LoadingData));
mLoadingDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mLoadingDlg.show();
if (null == mObbStateHandler)
mObbStateHandler = new OnObbStateChangeListener() {
public void onObbStateChange(String Path, int State) {
if (State == ERROR_INTERNAL) {
finish();
return;
}
if (State == ERROR_COULD_NOT_UNMOUNT) {
finish();
return;
}
if (State != MOUNTED && State != ERROR_ALREADY_MOUNTED) {
finish();
return;
}
DATA_PATH = SM.getMountedObbPath(Path);
...
if(!InitMenu()) {
finish();
return;
}
mLoadingDlg.dismiss();
onObb(OBBPath);
}
};
if (!SM.mountObb(OBBPath, null, mObbStateHandler)) finish();
}
...
方法2:
方法2 的原理很簡單, 就是於程式中 呼叫 StorageManager 之 mountObb() 後, 檢查 /mnt/obb 底下有無已經掛載的資料夾, 如下圖所示 (9e2fef3de9fbf43b3eb499af60893a00):
我在這兒使用 new Thread(new Runnable() 來檢查 /mnt/obb 底下有無已經掛載的資料夾 ( /mnt/obb/9e2fef3de9fbf43b3eb499af60893a00/ ) ; 約 15 秒後 timeout . 因為是 new Thread, 所以在處理 UI Dialog 時, Thread 要使用 mObbHandler 物件 sendMessage; mObbHandler 物件 以 overload 它的 handleMessage() 處理 Thread 傳來的 messages.
... private Handler mObbHandler = null; private OnObbStateChangeListener mObbStateHandler = null; private ProgressDialog mLoadingDlg = null; ... private void MountObb2(final String OBBPath) { final StorageManager SM = (StorageManager) getSystemService(STORAGE_SERVICE); /////////////////////////////////////////////////////////// // show dialog mLoadingDlg = new ProgressDialog(this); mLoadingDlg.setCancelable(true); mLoadingDlg.setMessage(getString(R.string.LoadingData)); mLoadingDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER); mLoadingDlg.show(); /////////////////////////////////////////////////////////// // send mountObb command if (null == mObbStateHandler) mObbStateHandler = new OnObbStateChangeListener() { public void onObbStateChange(String Path, int State) { if (State == ERROR_INTERNAL) { finish(); return; } if (State == ERROR_COULD_NOT_UNMOUNT) { finish(); return; } if (State != MOUNTED && State != ERROR_ALREADY_MOUNTED) { finish(); return; } } }; /////////////////////////////////////////////////////////// // new thread check if Obb mounted if (null == mObbHandler) mObbHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: finish(); break; case 1: ... break; case 2: if(!InitMenu()) { finish(); return; } break; case 3: mLoadingDlg.dismiss(); break; case 4: onObb(DATA_PATH); break; default: break; } } }; if (null != mObbHandler) new Thread(new Runnable() { public void run() { Message msg; int found = 0; for (int x=0; x < 15; x++) { try { Thread.sleep(1000); } catch(Exception e) { } File f = new File("/mnt/obb"); File[] files = f.listFiles(); for (File inFile : files) { if (inFile.isDirectory()) { DATA_PATH = "/mnt/obb/" + inFile.getName(); found = 1; msg = new Message(); msg.what = 1; if (!mObbHandler.sendMessage(msg)) finish(); break; } } if (1 == found) break; } if (0 == found) { finish(); //msg = new Message(); msg.what = 0; //if (!mObbHandler.sendMessage(msg)) finish(); return; } ... msg = new Message(); msg.what = 2; if (!mObbHandler.sendMessage(msg)) finish(); msg = new Message(); msg.what = 3; if (!mObbHandler.sendMessage(msg)) finish(); msg = new Message(); msg.what = 4; if (!mObbHandler.sendMessage(msg)) finish(); return; } }).start(); if (!SM.mountObb(OBBPath, null, mObbStateHandler)) finish(); } ...
onDestroy():
如果你的 App 是 Launcher 記得 onDestroy() 不要卸載 obb 了.
... @Override public void onDestroy() { super.onDestroy(); ...//((StorageManager) getSystemService(STORAGE_SERVICE)).unmountObb(OBB_PATH, true, OBBHandler);} ...
製作 Obb 檔案
https://developer.android.com/studio/command-line/jobb.html
jobb [-d <directory>][-o <filename>][-pn <package>][-pv <version>] \ [-k <key>][-ov][-dump <filename>][-v][-about]
@rem makeObb.bat jobb -d %CWD%/obb/ -o %CWD%/com.example.menu -pn com.examole.menu -pv 1 -v
執行上述 "jobb -d .... " 應該就可以產生 com.examole.menu.obb 這個檔案了.
習慣上 Obb 檔會置於 /storage/sdcard0/Android/obb/ 這個資料夾下. 以 com.examole.menu 為例:
Obb 檔案應當位於:
/storage/sdcard0/Android/obb/com.examole.menu/com.examole.menu.obb
留言列表