close

 

關於 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): 

 

MntObb.png

 

我在這兒使用 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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

arrow
arrow
    文章標籤
    obb jobb
    全站熱搜

    Lexra 發表在 痞客邦 留言(0) 人氣()