繁体   English   中英

未找到加载的动态功能的主要活动类

[英]Main activity class of loaded Dynamic feature is not found

我正在尝试向我的应用程序添加动态功能支持,因此我创建了一个测试应用程序。

测试应用程序有一个主应用程序部分,用于加载动态功能并尝试执行它。

功能模块将 MainActivityCalled 作为主要活动。

我得到的是功能加载过程有效,因为我收到了成功的日志消息,并且我得到了已安装模块的列表。

请注意,该应用程序是在虚拟设备上运行的,并没有发生真正的下载,我认为一切都是通过 AndroidStudio 的部署过程自动安装的。

事实是,我在尝试调用模块的主要活动时遇到这种错误:

W/System.err: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.dynamicfeature1/MainActivityCalled}; have you declared this activity in your AndroidManifest.xml?
W/System.err:     at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1805)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
    at android.app.Activity.startActivityForResult(Activity.java:4225)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
    at android.app.Activity.startActivityForResult(Activity.java:4183)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
    at android.app.Activity.startActivity(Activity.java:4522)
    at android.app.Activity.startActivity(Activity.java:4490)
    at com.example.mymodules.MainActivity$2.onClick(MainActivity.java:227)
    at android.view.View.performClick(View.java:5637)
    at android.view.View$PerformClick.run(View.java:22429)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)

一切都按照https://developer.android.com/guide/app-bundle/playcore#java上的文档完成,除了我猜测必须以意图执行的对模块活动的显式调用(没有示例上面链接的页面)。

您在下面找到的代码的重要部分是:

new OnSuccessListener<Integer>() {
                        @Override
                        public void onSuccess(Integer result) {
                            Log.d("request feature load","success "+result);
                            mySessionId=result;
                            Set<String> installedModules = splitInstallManager.getInstalledModules();
                            String[] modules = new String[installedModules.size()];

                            installedModules.toArray(modules);
                            for (int i=0;i<modules.length;i++)
                            {
                                Log.d("module",modules[i]);
                            }


                        }
                    })

那没问题。

然后

Button button2 = findViewById(R.id.fab2);
    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {



            Log.d("feature1","called");
            Intent intent=new Intent();
            intent.setClassName("com.example.dynamicfeature1","MainActivityCalled");

            try{  startActivity(intent);}
            catch (Exception e){
                e.printStackTrace();
            }

        }
    });

所有主要活动都有这个覆盖的方法

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
    Log.d("attachBaseContext",base.getPackageName().toString());
}

安装时不会在动态功能模块中调用。

我的代码有什么问题?

这是应用程序的主要活动

package com.example.mymodules;

...imports...

public class MainActivity extends AppCompatActivity {
private static int MY_REQUEST_CODE=1;
Activity activity;
int mySessionId;

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this);
 Log.d("attachBaseContext",base.getPackageName().toString());

}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == MY_REQUEST_CODE) {
        // Handle the user's decision. For example, if the user selects "Cancel",
        // you may want to disable certain functionality that depends on the module.
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    activity = this;
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    Button button1 = findViewById(R.id.button1);
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            // Creates an instance of SplitInstallManager.
            final SplitInstallManager splitInstallManager =
                    SplitInstallManagerFactory.create(activity);

// 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("dynamicfeature1")

                            .build();

// Creates a listener for request status updates.
            SplitInstallStateUpdatedListener listener =new SplitInstallStateUpdatedListener() {
                @Override
                public void onStateUpdate(SplitInstallSessionState state) {
                    if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
                        // Displays a dialog for the user to either “Download”
                        // or “Cancel” the request.
                        try {
                            splitInstallManager.startConfirmationDialogForResult(
                                    state,
                                    /* activity = */ activity,
                                    // You use this request code to later retrieve the user's decision.
                                    /* requestCode = */ MY_REQUEST_CODE);
                        } catch (IntentSender.SendIntentException e) {
                            e.printStackTrace();
                        }
                    }

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

                            case SplitInstallSessionStatus.INSTALLED:
                                Context tempNewContext=null;
                                try {
                                    tempNewContext = activity.createPackageContext(activity.getPackageName(), 0);
                                } catch (PackageManager.NameNotFoundException e) {

                                }
                                final Context newContext =tempNewContext;
                                // 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();


                                if (BuildCompat.isAtLeastO()) {
                                    // Updates the app’s context with the code and resources of the
                                    // installed module.
                                    SplitInstallHelper.updateAppInfo(newContext);
                                    new Handler().post(new Runnable() {
                                        @Override public void run() {
                                            // Loads contents from the module using AssetManager
                                            AssetManager am = newContext.getAssets();

                                        }
                                    });
                                } else
                                {SplitInstallHelper.updateAppInfo(newContext);}

                        }
                    }
                }

            } ;
            splitInstallManager.registerListener(listener);
            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(new OnSuccessListener<Integer>() {
                        @Override
                        public void onSuccess(Integer result) {
                            Log.d("request feature load","success "+result);
                            mySessionId=result;
                            Set<String> installedModules = splitInstallManager.getInstalledModules();
                            String[] modules = new String[installedModules.size()];

                            installedModules.toArray(modules);
                            for (int i=0;i<modules.length;i++)
                            {
                                Log.d("module",modules[i]);
                            }


                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        void checkForActiveDownloads() {
                            splitInstallManager
                                    // Returns a SplitInstallSessionState object for each active session as a List.
                                    .getSessionStates()
                                    .addOnCompleteListener(
                                            new OnCompleteListener<List<SplitInstallSessionState>>() {
                                                @Override
                                                public void onComplete(Task<List<SplitInstallSessionState>> 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.
                                                            }
                                                        }
                                                    }
                                                }


                                            });
                        }

                        @Override
                        public void onFailure(Exception e) {
Log.d("request feature load","failure "+e.getMessage());
                            switch (((SplitInstallException) e).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();
                            }

                        }
                    });




        }
    });
   Button button2 = findViewById(R.id.button2);
    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d("feature1","called");
 Intent intent=new Intent();
            intent.setClassName("com.example.dynamicfeature1","MainActivityCalled");

            try{  startActivity(intent);}
            catch (Exception e){
                e.printStackTrace();
            }

        }
    });
   Button button3 = findViewById(R.id.button3);
    button3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d("feature2","called");
        }
    });
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}



@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

这是主应用程序清单

<?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.example.mymodules">

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:name="com.google.android.play.core.splitcompat.SplitCompatApplication"
android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

</application>
</manifest>

然后是动态特征模块的MainActivity

package com.example.dynamicfeature1;

...imports...

public class MainActivityCalled extends AppCompatActivity {
@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
    Log.d("attachBaseContext",base.getPackageName().toString());
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "1-Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });
}

}

和模块清单

<?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.example.dynamicfeature1">

<dist:module
    dist:instant="false"
    dist:title="@string/title_dynamicfeature1">
    <dist:delivery>
        <dist:on-demand />
    </dist:delivery>

    <dist:fusing dist:include="false" />
</dist:module>

<application>
    <activity
        android:name=".MainActivityCalled"
        android:label="@string/title_activity_main"
        android:theme="@style/AppTheme.NoActionBar"></activity>
</application>

</manifest>

调用活动的正确指令是

intent. setClassName(BuildConfig.APPLICATION_ID, "com.example.dynamicfeature.MainActivityCalled");

它有效,活动被调用。

请注意 BuildConfig.APPLICATION_ID 是

com.example.mymodules

如果此字符串也用于动态模块中,则可以进行交叉调用:

- 从一个模块到另一个模块

- 从一个模块到主应用程序

但是你不想在模块中使用 BuildConfig.APPLICATION_ID 因为它有一个不同的值,所以主字符串值必须放入一个变量中。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM