• AndroidObb文件编程中使用详解
  • 制作Obb文件
  • 在代码中加入下载和读入Obb文件的逻辑
  • 1 下载DownloaderLibrary需要的包
  • 2 将Google Play License Library 与 Google Play Downloader Library导入到项目中
  • 注意
  • 在需要检查Obb文件的地方加入相关逻辑
  • 1 声明权限
  • 2 实现下载服务
  • 3 实现AlarmReceiver
  • 6 如果加入Activity状态改变逻辑
  • 7 接收下载进度


AndroidObb文件编程中使用详解

Obb文件是Google提供的将占存储空间较大的图片资源影音资源等制作成的压缩文件包,Obb文件可以在上架App时同时上传。当用户下载App时,Obb文件会随之下载,但是也会有不下载的情况,需要自行处理。

1.制作Obb文件

使用Jobb制作Obb文件在Android SDK中, %ANDROID——HOME/tools%中,在tools/bin下有jobb

命令:

jobb -d [目录名称的完整路径] -o [输出目标文件的完整路径] -pn [软件包名] -pv [包版本]

EG:
源文件目录 D:contents 目标文件夹: D:\obb\output.obb 软件包名 com.my.test 包版本 1

jobb -d D:\contents -o D:\obb\output.obb -pn com.my.test -pv 1

  • 注意:
  • jobb -d,-o 需要指定完整路径。如果指定相对路径,%ANDROID_HOME%/tools/将作为相对路径
  • JOBB工具如果不能输出有一定容量的.obb的文件的话,出现错误提示

2.在代码中加入下载和读入Obb文件的逻辑

2.1 下载DownloaderLibrary需要的包

Google提供了一个DownloaderLibrary来下载Obb文件。想使用DownloaderLibrary,现在在Android SDK Manager(Tools > Android > SDK Manager)中下载以下两个包:

  • Google Play Licenseing Library package
  • Google Play APK Expansion Library package

2.2 将Google Play License Library 与 Google Play Downloader Library导入到项目中

  • <sdk>/extras/google/market_licensing中存放的library对应为GooglePlayLicenseLibrary,将其作为Module导入到项目中
  • <sdk>/extras/google/market_apk_expansion中存放的downloader_library对应为DownloaderLibrary,将其作为module导入到项目中。

注意:

downloader_library在导入时,需要删除downloader_library/project.properties中的android.library.reference.1=../market_licensing
。当downloader_library导入之后,再将GooglePlayLicenseLibrary作为依赖项,加在downloader_library中。

3 在需要检查Obb文件的地方加入相关逻辑

以在MainActivity中判断为例:

3.1 声明权限

<manifest ...>
    <!-- Required to access Google Play Licensing -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />

    <!-- Required to download files from Google Play -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Required to keep CPU alive while downloading files
        (NOT to keep screen awake) -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <!-- Required to poll the state of the network connection
        and respond to changes -->
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- Required to check whether Wi-Fi is enabled -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <!-- Required to read and write the expansion files on shared storage -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

3.2 实现下载服务

  • 自定义下载服务继承自DownloaderService“
• `java 
 public class SampleDownloaderService extends DownloaderService { 
 // You must use the public key belonging to your publisher account 
 public static final String BASE64_PUBLIC_KEY = “YourLVLKey”; 
 // You should also modify this salt 
 public static final byte[] SALT = new byte[] { 1, 42, -12, -1, 54, 98, 
 -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84 
 };
@Override 
 public String getPublicKey() { 
 return BASE64_PUBLIC_KEY; 
 }
@Override 
 public byte[] getSALT() { 
 return SALT; 
 }
@Override 
 public String getAlarmReceiverClassName() { 
 return SampleAlarmReceiver.class.getName(); 
 } 
 }
* 在Manifest文件中声明服务

  ```java
<application ...>
    <service android:name=".SampleDownloaderService" />
    ...
</application>

3.3 实现AlarmReceiver

• 定义AlarmReceiver继承自BroadcastReceiver 
“`java 
 public class SampleAlarmReceiver extends BroadcastReceiver { 
 @Override 
 public void onReceive(Context context, Intent intent) { 
 try { 
 DownloaderClientMarshaller.startDownloadServiceIfRequired(context, 
 intent, SampleDownloaderService.class); 
 } catch (NameNotFoundException e) { 
 e.printStackTrace(); 
 } 
 } 
 }
* 在Manifest文件中声明receiver

  ```java
  <application ...>
    <receiver android:name=".SampleAlarmReceiver" />
    ...
</application>
  ```

### 3.4 判断Obb文件是否已经存在
* 封住装Obb文件信息

  ```java
  private static class XAPKFile {
        public final boolean mIsMain;
        public final int mFileVersion;
        public final long mFileSize;

        XAPKFile(boolean isMain, int fileVersion, long fileSize) {
            mIsMain = isMain;
            mFileVersion = fileVersion;
            mFileSize = fileSize;
        }
    }
  ```

* 定义Obb文件

  ```java
private static final XAPKFile[] xAPKS = {
            new XAPKFile(
                    true, // true signifies a main file
                    3, // the version of the APK that the file was uploaded
                       // against
                    687801613L // the length of the file in bytes
            ),
            new XAPKFile(
                    false, // false signifies a patch file
                    4, // the version of the APK that the patch file was uploaded
                       // against
                    512860L // the length of the patch file in bytes
            )            
    };
  • 判断Obb文件是否存在
• “`java 
 boolean expansionFilesDelivered() { 
 for (XAPKFile xf : xAPKS) { 
 String fileName = Helpers.getExpansionAPKFileName(this, xf.mIsBase, 
 xf.mFileVersion); 
 if (!Helpers.doesFileExist(this, fileName, xf.mFileSize, false)) 
 return false; 
 } 
 return true; 
 }
### 3.5 下载Obb文件

```java
// Check if expansion files are available before going any further
    if (!expansionFilesDelivered()) {
        // Build an Intent to start this activity from the Notification
        Intent notifierIntent = new Intent(this, MainActivity.getClass());
        notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                                Intent.FLAG_ACTIVITY_CLEAR_TOP);
        ...
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        // Start the download service (if required)
        int startResult =
            DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                        pendingIntent, SampleDownloaderService.class);
        // If download has started, initialize this activity to show
        // download progress
        if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
            // This is where you do set up to display the download
            // progress (next step)
            ...
            return;
        } // If the download wasn't necessary, fall through to start the app
    }
    startApp(); // Expansion files are available, start the app




<div class="se-preview-section-delimiter"></div>

3.6 如果加入Activity状态改变逻辑

@Override
protected void onResume() {
    if (null != mDownloaderClientStub) {
        mDownloaderClientStub.connect(this);
    }
    super.onResume();
}

@Override
protected void onStop() {
    if (null != mDownloaderClientStub) {
        mDownloaderClientStub.disconnect(this);
    }
    super.onStop();
}




<div class="se-preview-section-delimiter"></div>

3.7 接收下载进度

  • 定义IDwonloaderService
private IDownloaderService mRemoteService;
...
@Override
public void onServiceConnected(Messenger m) {
mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
}
  • 接收下载进度
    Activity需要实现IDownloaderClient接口
    “`java
    onDownloadProgress(DownloadProgressInfo progress) {
    //todo you can update your progress view
    }
* 接收下载状态  
Activity需要实现IDownloaderClient接口

  ```java
onDownloadStateChanged(int newState) {
    //todo you can judge whether the obb download service is ok or other states
}

参考链接

### 3.7 接收下载进度

* 定义IDwonloaderService

  ```java
  private IDownloaderService mRemoteService;
...
@Override
public void onServiceConnected(Messenger m) {
    mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
    mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
}
  ```

* 接收下载进度  
Activity需要实现IDownloaderClient接口

  ```java
onDownloadProgress(DownloadProgressInfo progress) {
    //todo you can update your progress view
}
  • 接收下载状态
    Activity需要实现IDownloaderClient接口
onDownloadStateChanged(int newState) {
//todo you can judge whether the obb download service is ok or other states
}

参考链接
参考源码