如何启动Manifest中提到的不存在的Activity?

Hec*_*tor 8 android

我正在尝试开发一个"动态"Android应用程序.

动态,我在清单中列出了一个在运行时"构建"的活动.

我可以很好地构建所需的活动,但是,当我尝试启动它时,我的应用程序失败了......

    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.research.ps/com.research.Dynamic}: java.lang.ClassNotFoundException: 
Didn't find class "com.research.Dynamic" on path: DexPathList[[zip file "/data/app/com.research.ps-1/base.apk"],nativeLibraryDirectories=[/data/app/com.research.ps-1/lib/arm, 
/data/app/com.research.ps-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以在运行时成功实例化Android Activity?

有没有办法在我的应用程序路径中添加"临时"或"shell"活动?然后用我的动态实例替换"临时"活动?

UPDATE

My Manifest XML包含此条目

<activity
  android:name=".Dynamic"
  android:label="@string/title_activity_dynamic"
  android:theme="@style/AppTheme.NoActionBar" />
Run Code Online (Sandbox Code Playgroud)

但是,我的应用程序中没有包含名为"Dynamic"的Activity.

我正在使用ByteBuddy构建我的动态活动: -

  final Class<? extends android.support.v7.app.AppCompatActivity> dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
            .subclass(android.support.v7.app.AppCompatActivity.class, IMITATE_SUPER_CLASS)
            .name("com.research.Dynamic")
            .make()
            .load(getClass().getClassLoader(), new AndroidClassLoadingStrategy.Wrapping(this.getDir("dexgen", Context.MODE_PRIVATE)))
            .getLoaded();

final Intent intent = new Intent(this, dynamicType);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)

Jon*_*win 12

是的,你CAN开始这样的Activity(假设你有一个虚拟清单 Activity条目).
如果您不喜欢这种技术,请使用Fragments(它们不需要清单中的条目).
或者使用像Apache Cordova等人的WebViewJavaScript(跨平台!).ByteBuddy(也是Byte Buddy的@Rafael Winterhalter的作者)看起来很酷,也许是一个学习曲线.为什么不下载链接的项目并尝试这两种技术. 以下是Android Studio 项目()中的方法:

include ByteBuddyGradlebuild.gradle

android {
    compileSdkVersion 25
    buildToolsVersion '25'
    dependencies {
        compile 'com.android.support:appcompat-v7:25'
        compile 'net.bytebuddy:byte-buddy:1.7.9'
        compile 'net.bytebuddy:byte-buddy-android:1.7.9'
    }
}
Run Code Online (Sandbox Code Playgroud)

我如何在运行时"找到"我的动态实例化类?

外部加载DEX文件(类字节代码)

在这里查看我的答案并按照源代码和教程的链接(Apache Ant { Eclipsecompatible,build.xml}和Android Studio 相同代码的Gradle示例build.gradle,您需要一些这些项目提供的自定义构建步骤).
代码段:

        // Internal storage where the DexClassLoader writes the optimized dex file to.
        final File optimizedDexOutputPath = getDir(SECONDARY_DEX_INTERNAL_DIR, Context.MODE_PRIVATE);

        // Initialize the class loader with the secondary dex file.
        DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
                                                optimizedDexOutputPath.getAbsolutePath(),
                                                null,
                                                getClassLoader());
        Class libProviderClazz = null;//variable libProviderClazz of type Class

        try {
            // Load the library class from the class loader.
            libProviderClazz = cl.loadClass(PROVIDER_CLASS);

            // Cast the return object to the library interface so that the
            // caller can directly invoke methods in the interface.

            // Alternatively, the caller can invoke methods through reflection,
            // which is more verbose and slow.
            LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance();

        }
        catch (Exception exception)
        {
            // Handle exception gracefully here.
            exception.printStackTrace();
        }
Run Code Online (Sandbox Code Playgroud)

问:如何添加活动,我无法将其添加到清单中?
答:使用片段,它们不需要清单中的条目.


Hec*_*tor 5

我已设法调用动态实例化的Activity并使用ByteBuddy设置所需的布局内容.

这是如何做

final DynamicType.Unloaded<? extends AppCompatActivity> dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
        .subclass(AppCompatActivity.class)
        .name(CLASS_NAME)
        .method(named("onCreate").and(takesArguments(1)))
        .intercept(MethodDelegation.to(TargetActivity.class).andThen(SuperMethodCall.INSTANCE))
        .make();

final Class<? extends AppCompatActivity> dynamicTypeClass = dynamicType.load(getClassLoader(), new AndroidClassLoadingStrategy.Injecting(this.getDir("dexgen", Context.MODE_PRIVATE))).getLoaded();

final Intent intent = new Intent(this, dynamicTypeClass);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)

方法委托类

public class TargetActivity {

    public static void intercept(Bundle savedInstanceState, @This AppCompatActivity thiz) {
        thiz.setContentView(R.layout.activity_fourth);
    }
}
Run Code Online (Sandbox Code Playgroud)

即使这给出了期望的结果,它仍然存在问题,因为super.onCreate(savedInstanceState)在我打电话之后进行了呼叫setContent(我认为).

使用优秀的ByteBuddy库是一种比使用DEX操作更好的方法.