App Bundle

App bundle 总结

1  简介

https://developer.android.com/platform/technology/app-bundle

官网列举的采用app bundle技术的应用:

App Bundle

App Bundle

2 Getting started

  1. Download Android Studio 3.2 or higher—it's the easiest way to add dynamic feature modules and build app bundles.
  2. Add support for Dynamic Delivery by including a base module, organizing code and resources for configuration APKs, and, optionally, adding dynamic feature modules.
  3. Build an Android App Bundle using Android Studio. If you're not using the IDE, you can instead build an app bundle from the command line.
  4. Test your Android App Bundle using bundletool to generate APKs from your app bundle and deploy them to a connected device.
  5. Enroll into app signing by Google Play. Otherwise, you can't upload your app bundle to the Play Console.
  6. Upload your app bundle to the Play Console. You can then use the Play Console's new internal test track to quickly test downloading your app via Dynamic Delivery.

 

 

https://android.jlelse.eu/a-practical-guide-to-android-app-bundle-for-beginners-7e8d93831828

 

2.2 添加支持

When downloading dynamic feature modules on demand, devices running Android 6.0 (API level 23) and lower require the app to restart before completing installation of the new modules. However, if you want to be able to access the downloaded module’s code and resources immediately after it’s downloaded, you should include support for the SplitCompat library in your manifest. To learn more, read Access code and resources from downloaded modules.

 

2.2.1 添加Play core 依赖

implementation 'com.google.android.play:core:1.4.1'

2.2.2 发起需求模块请求

// Creates an instance of SplitInstallManager.

SplitInstallManager splitInstallManager =

    SplitInstallManagerFactory.create(context);



// Creates a request to install a module.

SplitInstallRequest request =

    SplitInstallRequest

        .newBuilder()

        // You can download multiple on demand modules per

        // request by invoking the following method for each

        // module you want to install.

        .addModule("pictureMessages")

        .addModule("promotionalFilters")

        .build();



splitInstallManager

    // Submits the request to install the module through the

    // asynchronous startInstall() task. Your app needs to be

    // in the foreground to submit the request.

    .startInstall(request)

    // You should also be able to gracefully handle

    // request state changes and errors. To learn more, go to

    // the section about how to Monitor the request state.

    .addOnSuccessListener(sessionId -> { ... })

    .addOnFailureListener(exception -> { ... });

 

延迟请求

// Requests an on demand module to be downloaded when the app enters

// the background. You can specify more than one module at a time.

splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));

2.2.3 监听请求结果

// Initializes a variable to later track the session ID for a given request.

int mySessionId = 0;



// Creates a listener for request status updates.

SplitInstallStateUpdatedListener listener = state -> {

    if (state.sessionId() == mySessionId) {

      // Read the status of the request to handle the state update.

    }

};



// Registers the listener.

splitInstallManager.registerListener(listener);



...



splitInstallManager

    .startInstall(request)

    // When the platform accepts your request to download

    // an on demand module, it binds it to the following session ID.

    // You use this ID to track further status updates for the request.

    .addOnSuccessListener(sessionId -> { mySessionId = sessionId; })

    // You should also add the following listener to handle any errors

    // processing the request.

    .addOnFailureListener(exception -> {

        // Handle request errors.

    });



// When your app no longer requires further updates, unregister the listener.

splitInstallManager.unregisterListener(listener);

 

1 错误处理

splitInstallManager

    .startInstall(request)

    .addOnFailureListener(exception -> {

        switch (((SplitInstallException) exception).getErrorCode()) {

            case SplitInstallErrorCode.NETWORK_ERROR:

                // Display a message that requests the user to establish a

                // network connection.

                break;

            case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED:

                checkForActiveDownloads();

            ...

    });



void checkForActiveDownloads() {

    splitInstallManager

        // Returns a SplitInstallSessionState object for each active session as a List.

        .getSessionStates()

        .addOnCompleteListener( task -> {

            if (task.isSuccessful()) {

                // Check for active sessions.

                for (SplitInstallSessionState state : task.getResult()) {

                    if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {

                        // Cancel the request, or request a deferred installation.

                    }

                }

            }

        });

}

2 状态监听

@Override

public void onStateUpdate(SplitInstallSessionState state) {

    if (state.status() == SplitInstallSessionStatus.FAILED

        && state.errorCode() == SplitInstallErrorCode.SERVICE_DIES) {

       // Retry the request.

       return;

    }

    if (state.sessionId() == mySessionId) {

        switch (state.status()) {

            case SplitInstallSessionStatus.DOWNLOADING:

              int totalBytes = state.totalBytesToDownload();

              int progress = state.bytesDownloaded();

              // Update progress bar.

              break;



            case SplitInstallSessionStatus.INSTALLED:



              // After a module is installed, you can start accessing its content or

              // fire an intent to start an activity in the installed module.

              // For other use cases, see access code and resources from installed modules.



              // If the request is an on demand module for an Android Instant App

              // running on Android 8.0 (API level 26) or higher, you need to

              // update the app context using the SplitInstallHelper API.

        }

    }

}

3 用户确认

@Override void onSessionStateUpdate(SplitInstallSessionState state) {
   
if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
       
// Displays a dialog for the user to either “Download”
        // or “Cancel” the request.
        splitInstallManager.startConfirmationDialogForResult(
          state,
         
/* activity = */ this,
         
// You use this request code to later retrieve the user's decision.
          /* requestCode = */ MY_REQUEST_CODE);
    }
    ...
 }

4

2.2.4 Immediately access modules

需要SplitCompat Library 资源

整体配置

方式1:

声明 SplitCompatApplication

<application
    ...
   
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>

方式2:

public class MyApplication extends SplitCompatApplication {

    ...

}

 

 

动态模块下载完后立即可以访问。

 

单独配置组件Activity或者Service

重载attachBaseContext

@Override

protected void attachBaseContext(Context base) {

    super.attachBaseContext(base);

    // Emulates installation of future on demand modules using SplitCompat.

    SplitCompat.install(this);

}

访问下载的模块资源:

需要先刷新app 的context

case SplitInstallSessionStatus.INSTALLED:

                Context newContext = context.createPackageContext(context.getPackageName(), 0);

                // If you use AssetManager to access your app’s raw asset files, you’ll need

                // to generate a new AssetManager instance from the updated context.

                AssetManager am = newContext.getAssets();

        }

新启动的模块不需要:

 

加载so文件:

public void onStateUpdate(SplitInstallSessionState state) {

    if (state.sessionId() == mySessionId) {

        switch (state.status()) {

            case SplitInstallSessionStatus.INSTALLED:

                // Updates the app’s context as soon as a module is installed.

                Context newContext = context.createPackageContext(context.getPackageName(), 0);

                // To load C/C++ libraries from an installed module, use the following API

                // instead of System.load().

                SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”);

                ...

        }

    }

}

 

2.2.5 管理安装的模块

Set<String> installedModules = splitInstallManager.getInstalledModules();

 

卸载模块:

// Specifies two dynamic feature modules for deferred uninstall.

splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));

3 API

5个包:

App Bundle

 

3.1 com.google.android.play.core.splitinstall

安装动态模块及设置监听

3.2 com.google.android.play.core.splitcompat

两个类,调用可以使应用不必重启即可访问动态下载的模块:

SplitCompat    

SplitCompatApplication