5

为了将我的游戏应用程序分解为即时和可安装版本,我开始使用动态模块拆分 API 交付。我一直在关注这里的 Codelabs 教程https://codelabs.developers.google.com/codelabs/on-demand-dynamic-delivery/index.html#0。不幸的是,它使用 Kotlin 来编写 MainActivity 代码,它不如 Java 特定,但如果你已经完成了 Kotlin 教程,仍然相当容易理解。该示例包括使用以下内容访问“资产”功能模块中“资产”文件夹中的文本图块:

private const val packageName = "com.google.android.samples.dynamicfeatures.ondemand"

val assetManager = createPackageContext(packageName, 0).assets
// Now treat it like any other asset file.
val assets = assetManager.open("assets.txt")
val assetContent = assets.bufferedReader()
           .use {
               it.readText()
           }

现在我只想访问动态功能模块的可绘制文件夹中的图形文件。我只会使用我的动态功能模块来存储大型图形,这将使我超过 10 MG 的即时应用程序下载限制。最干净的方法是什么?

主“应用程序”模块:

在此处输入图像描述

“应用程序”中的 Java 代码:

loadTexture(R.drawable.aaa_image);

Bitmap bitmap;
public void loadTexture(final int resourceId){
    bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
    ***

动态交付的“installationassets”模块:

在此处输入图像描述

'app'中的Java代码仍然无法到达:

 loadTexture(R.drawable.testgraphic);
 cannot resolve symbol 'testgraphic'
4

4 回答 4

8

我找到了一个从功能模块资源加载可绘制对象的有效解决方案。诀窍是为模块使用正确的包名称。

例子:

  • 基本模块包名是“ com.project
  • build.gradle 中定义的功能模块名称“ FeatureModule
  • 功能模块包名称“ com.project.FeatureModule

构建.gradle

dynamicFeatures = [":FeatureModule"]

爪哇

int drawableResId = context.getResources().getIdentifier("your_drawable_name", "drawable", "com.project.FeatureModule");
context.getDrawable(drawableResId);

参考文章

于 2020-02-14T14:06:49.013 回答
2

传统上,您不能从另一个模块访问资源,只能访问资产(原始存储)。现在显然你可以,但它很乱。然而,拆分 API 安排的全部意义在于,您确实可以访问所有部分(模块)的代码和资源,就像它们在哪里一样。我发现资产文件夹确实如此,因为您不需要为动态模块引用动态创建新上下文。我发现如果您的主即时模块资产文件夹和动态即时模块资产文件夹中恰好有相同的标题资产,那么它是从动态模块中提取的。

但是,我仍然无法从动态模块资源 (R) 中提取信息,但我会提供一种解决方法来回答我自己的问题,直到找到示例或获得更好的答案。您可以将图像文件放在动态模块的资产文件夹中,然后按如下方式提取和转换它们:

loadTextureResource("testimage.png");//include file type (.png)

Bitmap bitmap;
public void loadTextureResource(String imagename){

    ImageView mImage=new ImageView(context);
    InputStream ims;

    try {
        // get input stream
        ims = context.getAssets().open(imagename);
        // load image as Drawable
        Drawable d = Drawable.createFromStream(ims, null);
        // set image to ImageView
        mImage.setImageDrawable(d);

        bitmap = ((BitmapDrawable)mImage.getDrawable()).getBitmap();
        ***
于 2019-08-27T20:23:38.090 回答
0

com.android.application模块并不意味着访问模块的com.android.dynamic-feature资源,因为应用程序无法访问动态功能模块的资源表。

于 2019-09-11T13:00:58.390 回答
0

@pumnao 发布的答案的改进,我仍然设法发现有点混乱。也许这会帮助下一个疲惫的旅行者。

如果您的应用程序/基础build.gradle包括以下内容:

dynamicFeatures = [':dynamicfeature']

然后你可以像这样加载资源dynamicfeature

val splitManager = SplitInstallManagerFactory.create(context)
val featureName = "dynamicfeature"
val installed = splitManager.installedModules.contains(featureName)

if (installed) {
  val refreshedContext = context.createPackageContext(context.packageName, 0)
  val packageName = "${context.applicationContext.packageName}.$featureName"

  val drawableId = refreshedContext.resources.getIdentifier(
    "your_drawable_name", "drawable", packageName
  )
  val drawable = refreshedContext.getDrawable(drawableId)
}

以下是有趣的行。请注意,我们使用packageNameofapplicationContext作为前缀。

val packageName = "${context.applicationContext.packageName}.$featureName"
于 2021-07-21T00:53:43.820 回答