简体   繁体   English

Android 动态特性模块不工作,无法正常访问资源

[英]Android dynamic feature modules do not work, cannot access resources properly

I am having trouble accessing a resource located in dynamic feature raw folder from my main activity.我无法从我的主要活动访问位于动态功能原始文件夹中的资源。 The installation of the dynamic feature works fine and I can access it immediately with application context but I cannot access it any more after I have restarted my app.动态功能的安装工作正常,我可以立即使用应用程序上下文访问它,但在我重新启动我的应用程序后我无法再访问它。

The dynamic feature has no classes, only a data.json file.动态特征没有类,只有一个 data.json 文件。

My test procedure:我的测试程序:

  • Activity "ActivityFromBase" starts "Activity2" with startActivity2活动“ActivityFromBase”以 startActivity2 启动“Activity2”
  • Activity2 installs dynamic features with installDynamicFeature(); Activity2 使用 installDynamicFeature() 安装动态特性;
  • After installation runTest() of Activity2 outputs: fromApplicationContext: 2113994755 fromContext: 0 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 2113994755 fromNewContext4: 2113994755安装后 Activity2 的 runTest() 输出: fromApplicationContext: 2113994755 fromContext: 0 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 2113994755 fromNewContext4: 2113994755
  • When Activity2 is closed runTest() of ActivityFromBase outputs the same: fromApplicationContext: 2113994755 fromContext: 0 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 2113994755 fromNewContext4: 2113994755当 Activity2 关闭时,ActivityFromBase 的 runTest() 输出相同: fromApplicationContext: 2113994755 fromContext: 0 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 2113994755 fromNewContext4: 2113994755
  • When the app is restarted runTest() of ActivityFromBase outputs: fromApplicationContext: 0 fromContext: 0 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 0 fromNewContext4: 0当应用程序重新启动时,ActivityFromBase 的 runTest() 输出: fromApplicationContext: 0 fromContext: 0 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 0 fromNewContext4: 0
  • Activity "ActivityFromBase" starts "Activity2" with startActivity2活动“ActivityFromBase”以 startActivity2 启动“Activity2”
  • runTest() of Activity2 outputs: fromApplicationContext: 0 fromContext: 2113994755 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 0 fromNewContext4: 0 Activity2 的 runTest() 输出: fromApplicationContext: 0 fromContext: 2113994755 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 0 fromNewContext4: 0
  • When Activity2 is closed runTest() of ActivityFromBase outputs the same: fromApplicationContext: 0 fromContext: 2113994755 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 0 fromNewContext4: 0当 Activity2 关闭时,ActivityFromBase 的 runTest() 输出相同: fromApplicationContext: 0 fromContext: 2113994755 fromNewContext: 0 fromNewContext2: 0 fromNewContext3: 0 fromNewContext4: 0

My questions:我的问题:

  • Any idea why I cannot access the resource from ActivityFromBase until Activity2 is opened at least once?知道为什么在 Activity2 至少打开一次之前我无法从 ActivityFromBase 访问资源吗? Please note that I have cut out and simplified the original code but this is the basic code relevant for this problem.请注意,我已经删除并简化了原始代码,但这是与此问题相关的基本代码。
  • Which is the correct context to use for getResources() and for the packageName of getIdentifier() after dynamic installation and after restart?在动态安装和重启后,哪个是用于 getResources() 和 getIdentifier() 的 packageName 的正确上下文?
  • Why is SplitCompat.install(this) needed in attachBaseContext?为什么在 attachBaseContext 中需要 SplitCompat.install(this)? I thought it is only needed for classes in the dynamic feature and not for resources.我认为它只需要动态特性中的类而不是资源。
public class ActivityFromBase extends AppCompatActivity {
    public void startActivity2() {
        Intent intent = new Intent(activity, Activity2.class);
        startActivityForResult(intent, 1);      
    }   

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        testAccessResource(this);
    }
    
    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        SplitCompat.install(this);
    }

    final public static String dynamicResourceName="dynamicResources";
    final public static String dynamicResourcePackageName="com.app."+dynamicResourceName;

    public static int getRawResourceFromPackage(final Context context, String name, String packageName) {
        return context.getResources().getIdentifier(name, "raw", packageName);
    }
    
    static public int testAccessResource(final Context context) {
            String name="data";
            
            int fromApplicationContext=getRawResourceFromPackage(context.getApplicationContext(), name,  dynamicResourcePackageName);
            int fromContext=getRawResourceFromPackage(context, name,  resourceIDWithContext.context.getPackageName()+"."+dynamicResourceName);
            int fromNewContext=0;
            int fromNewContext2=0;
            int fromNewContext3=0;
            int fromNewContext4=0;
            int fromNewContext5=0;
            try {
                Context newContext = context.createPackageContext(context.getPackageName(), 0);
                fromNewContext=getRawResourceFromPackage(newContext, name,  context.getPackageName()+"."+dynamicResourceName);
                Context newContext2 = context.getApplicationContext().createPackageContext(context.getApplicationContext().getPackageName(), 0);
                fromNewContext2=Tools.getRawResourceFromPackage(newContext2, name,  context.getApplicationContext().getPackageName()+"."+Tools.dynamicResourceName);
                fromNewContext3=Tools.getRawResourceFromPackage(context.getApplicationContext(), name,  context.getApplicationContext().getPackageName()+"."+Tools.dynamicResourceName);
                fromNewContext4=Tools.getRawResourceFromPackage(context.getApplicationContext(), name,  dynamicResourcePackageName);
                fromNewContext5=Tools.getRawResourceFromPackage(newContext, name,  context.getApplicationContext().getPackageName()+"."+Tools.dynamicResourceName);
            } catch (PackageManager.NameNotFoundException e) {
            }
            String message="fromApplicationContext: "+String.valueOf(fromApplicationContext)+" fromContext: "+String.valueOf(fromContext)+" fromNewContext: "+String.valueOf(fromNewContext)+" fromNewContext2: "+String.valueOf(fromNewContext2)+" fromNewContext3: "+String.valueOf(fromNewContext3)+" fromNewContext4: "+String.valueOf(fromNewContext4)+" fromNewContext5: "+String.valueOf(fromNewContext5);
            Log.d("dynamic",message);
    }

}
public class Activity2 extends Activity {
    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        SplitCompat.install(this);
    }

    public void runTest() {
        testAccessResource(this);
    }

    public void installDynamicFeature() {
        SplitInstallManager splitInstallManager;
        splitInstallManager =  SplitInstallManagerFactory.create(this);
        SplitInstallRequest request =
                SplitInstallRequest
                        .newBuilder()
                        .addModule(ActivityFromBase.dynamicResourceName)
                        .build();

        SplitInstallStateUpdatedListener listener = state -> {
            if (state.status()== SplitInstallSessionStatus.INSTALLED) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    SplitInstallHelper.updateAppInfo(this);
                }
            } 
        };
        splitInstallManager.registerListener(listener);

        splitInstallManager
                .startInstall(request);
    }
}

AndroidManifest of dynamic feature动态特性的AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    package="com.app.dynamicresources">

    <application android:hasCode="false"/>

    <dist:module
        dist:instant="false"
        dist:title="@string/title_dynamicresources">
        <dist:delivery>
            <dist:on-demand />
        </dist:delivery>
        <dist:fusing dist:include="true" />
    </dist:module>
</manifest>

AndroidManifest of app应用程序的AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app">
    <application
        android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
        <activity
            android:name=".ActivityFromBase"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:theme="@style/Theme.AppCompat.NoActionBar"
            android:exported="true">
        <activity
            android:name=".Activity2"
            android:parentActivityName=".ActivityFromBase"
            android:theme="@style/Theme.AppCompat.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.app.ActivityFromBase" />
        </activity>
    </application>
</manifest>

After dozens of uploads to the internal test track I was able to identify the reason.在将数十次上传到内部测试轨道后,我能够找出原因。 Somehow the AdMob initialization destroys the resource access if it is done too late.如果 AdMob 初始化完成得太晚,它会以某种方式破坏资源访问。 attachBaseContext is called before onCreate method of the activity so the solution was to do the AdMob initialization there: attachBaseContext 在活动的 onCreate 方法之前被调用,所以解决方案是在那里进行 AdMob 初始化:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(newBase);
    MobileAds.initialize(this, ...
    SplitCompat.install(context);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 动态特征模块第三方库无法访问资源 - Third party library of dynamic feature module cannot access resources Android Studio-Canary 8:无法访问功能模块和库模块中的资源 - Android Studio - Canary 8: Can't access the resources in feature modules and library modules Android 动态特性模块依赖 - Android dynamic feature modules dependencies App Bundle动态功能模块中的访问资源 - Access Resources In Dynamic Feature Module of App Bundle 无法访问动态功能模块的资源 - Unable to access resources of dynamic-feature module Android 带匕首刀柄的动态功能模块 - Android Dynamic Feature modules with Dagger Hilt 如何在功能模块中对 Android 资源进行单元测试? - How can I unit test Android resources in feature modules? 在 Android 上添加模块作为动态功能时找不到资源 - Resources not found when adding a module as a dynamic feature on Android 无法访问动态功能中的android.support.v4.view.KeyEventDispatcher.Component - Cannot access android.support.v4.view.KeyEventDispatcher.Component in Dynamic Feature 具有 Android 架构导航的动态功能模块之间的 startActivityForResult() - startActivityForResult() between Dynamic Feature Modules with Android Architecture Navigation
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM