From 96414325fb330397db50d50fe1475145e09091c6 Mon Sep 17 00:00:00 2001
From: shifujun <shifujun@foxmail.com>
Date: Fri, 24 Dec 2021 16:14:42 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat(core.manifest-parser):=20=E5=AE=9E?=
 =?UTF-8?q?=E7=8E=B0=E7=BC=96=E8=AF=91=E6=9C=9F=E8=A7=A3=E6=9E=90=E6=8F=92?=
 =?UTF-8?q?=E4=BB=B6Manifest=E7=94=9F=E6=88=90java=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

通过PluginClassLoader新增方法loadPluginManifest可加载该类。

#696
---
 projects/sdk/core/gradle-plugin/build.gradle  |   1 +
 .../shadow/core/gradle/ShadowPlugin.kt        |  42 ++
 .../core/gradle/PackageMultiPluginTest.kt     |   1 +
 .../core/gradle/PackageOnlyPluginTest.kt      |   1 +
 .../core/gradle/PackagePluginTaskTest.kt      |   1 +
 .../loader/classloaders/PluginClassLoader.kt  |   6 +
 projects/sdk/core/manifest-parser/.gitignore  |   1 +
 .../sdk/core/manifest-parser/build.gradle     |  22 ++
 .../manifest_parser/AndroidManifestKeys.kt    |  25 ++
 .../manifest_parser/AndroidManifestReader.kt  | 177 +++++++++
 .../core/manifest_parser/ManifestParser.kt    |  18 +
 .../PluginManifestGenerator.kt                | 361 ++++++++++++++++++
 .../src/test/java/android/R.java              |   7 +
 .../java/android/content/pm/ActivityInfo.java |  42 ++
 .../test/java/android/view/WindowManager.java |  21 +
 .../shadow/sample/plugin/app/lib/R.java       |   7 +
 .../AndroidManifestReaderTest.kt              |  17 +
 .../PluginManifestGeneratorTest.kt            |  40 ++
 .../resources/case_as_little_as_possible.xml  |   7 +
 .../test/resources/noAppComponentFactory.xml  |   7 +
 .../src/test/resources/sample-app.xml         | 102 +++++
 .../shadow/core/runtime/PluginManifest.java   | 142 +++++++
 projects/sdk/core/settings.gradle             |   1 +
 .../test-plugin-androidx-cases/build.gradle   |   4 +
 .../test-plugin-general-cases/build.gradle    |   4 +
 .../plugin-service-for-host/build.gradle      |   6 +
 26 files changed, 1063 insertions(+)
 create mode 100644 projects/sdk/core/manifest-parser/.gitignore
 create mode 100644 projects/sdk/core/manifest-parser/build.gradle
 create mode 100644 projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestKeys.kt
 create mode 100644 projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReader.kt
 create mode 100644 projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/ManifestParser.kt
 create mode 100644 projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGenerator.kt
 create mode 100644 projects/sdk/core/manifest-parser/src/test/java/android/R.java
 create mode 100644 projects/sdk/core/manifest-parser/src/test/java/android/content/pm/ActivityInfo.java
 create mode 100644 projects/sdk/core/manifest-parser/src/test/java/android/view/WindowManager.java
 create mode 100644 projects/sdk/core/manifest-parser/src/test/java/com/tencent/shadow/sample/plugin/app/lib/R.java
 create mode 100644 projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReaderTest.kt
 create mode 100644 projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGeneratorTest.kt
 create mode 100644 projects/sdk/core/manifest-parser/src/test/resources/case_as_little_as_possible.xml
 create mode 100644 projects/sdk/core/manifest-parser/src/test/resources/noAppComponentFactory.xml
 create mode 100644 projects/sdk/core/manifest-parser/src/test/resources/sample-app.xml
 create mode 100644 projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PluginManifest.java

diff --git a/projects/sdk/core/gradle-plugin/build.gradle b/projects/sdk/core/gradle-plugin/build.gradle
index b3f479cd7..1339d6feb 100644
--- a/projects/sdk/core/gradle-plugin/build.gradle
+++ b/projects/sdk/core/gradle-plugin/build.gradle
@@ -16,6 +16,7 @@ dependencies {
     implementation "com.android.tools.build:gradle:$build_gradle_version"
     implementation 'com.googlecode.json-simple:json-simple:1.1'
     implementation project(':transform')
+    implementation project(':manifest-parser')
     testImplementation 'junit:junit:4.12'
     testImplementation gradleTestKit()
 
diff --git a/projects/sdk/core/gradle-plugin/src/main/kotlin/com/tencent/shadow/core/gradle/ShadowPlugin.kt b/projects/sdk/core/gradle-plugin/src/main/kotlin/com/tencent/shadow/core/gradle/ShadowPlugin.kt
index 665fb4ba4..f568c4999 100644
--- a/projects/sdk/core/gradle-plugin/src/main/kotlin/com/tencent/shadow/core/gradle/ShadowPlugin.kt
+++ b/projects/sdk/core/gradle-plugin/src/main/kotlin/com/tencent/shadow/core/gradle/ShadowPlugin.kt
@@ -18,14 +18,18 @@
 
 package com.tencent.shadow.core.gradle
 
+import com.android.build.gradle.AppExtension
 import com.android.build.gradle.AppPlugin
 import com.android.build.gradle.BaseExtension
+import com.android.build.gradle.tasks.ProcessMultiApkApplicationManifest
 import com.tencent.shadow.core.gradle.extensions.PackagePluginExtension
+import com.tencent.shadow.core.manifest_parser.generatePluginManifest
 import com.tencent.shadow.core.transform.ShadowTransform
 import com.tencent.shadow.core.transform_kit.AndroidClassPoolBuilder
 import com.tencent.shadow.core.transform_kit.ClassPoolBuilder
 import org.gradle.api.*
 import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.provider.Property
 import java.io.File
 import kotlin.reflect.full.declaredFunctions
 import kotlin.reflect.jvm.isAccessible
@@ -61,6 +65,8 @@ class ShadowPlugin : Plugin<Project> {
             initAndroidClassPoolBuilder(baseExtension, project)
 
             createPackagePluginTasks(project)
+
+            createGeneratePluginManifestTasks(project)
         }
     }
 
@@ -83,6 +89,42 @@ class ShadowPlugin : Plugin<Project> {
         }
     }
 
+    private fun createGeneratePluginManifestTasks(project: Project) {
+        val appExtension: AppExtension = project.extensions.getByType(AppExtension::class.java)
+        appExtension.applicationVariants.filter { variant ->
+            variant.productFlavors.any { flavor ->
+                flavor.dimension == ShadowTransform.DimensionName &&
+                        flavor.name == ShadowTransform.ApplyShadowTransformFlavorName
+            }
+        }.forEach { pluginVariant ->
+            val output = pluginVariant.outputs.first()
+            val processManifestTask = output.processManifestProvider.get()
+            val manifestFile = (processManifestTask as ProcessMultiApkApplicationManifest).mainMergedManifest.get().asFile
+            val variantName = manifestFile.parentFile.name
+            val outputDir = File(project.buildDir, "generated/source/pluginManifest/$variantName")
+
+            // 添加生成PluginManifest.java任务
+            val task = project.tasks.register("generate${variantName.capitalize()}PluginManifest") {
+                it.dependsOn(processManifestTask)
+                it.inputs.file(manifestFile)
+                it.outputs.dir(outputDir).withPropertyName("outputDir")
+                val packageForR = (project.tasks.getByName("processPluginDebugResources").property("namespace") as Property<String>).get()
+                it.doLast {
+                    generatePluginManifest(manifestFile,
+                            outputDir,
+                            "com.tencent.shadow.core.manifest_parser",
+                            packageForR)
+                }
+            }
+            project.tasks.getByName("compile${variantName.capitalize()}JavaWithJavac").dependsOn(task)
+
+            // 把PluginManifest.java添加为源码
+            appExtension.sourceSets.getByName(variantName).java {
+                srcDir(outputDir)
+            }
+        }
+    }
+
     private fun addFlavorForTransform(baseExtension: BaseExtension) {
         baseExtension.flavorDimensionList.add(ShadowTransform.DimensionName)
         try {
diff --git a/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageMultiPluginTest.kt b/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageMultiPluginTest.kt
index b3c22bda4..fe962d9a5 100644
--- a/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageMultiPluginTest.kt
+++ b/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageMultiPluginTest.kt
@@ -47,6 +47,7 @@ class PackageMultiPluginTest {
                 .withProjectDir(ROOT_PROJECT_DIR)
                 .withPluginClasspath()
                 .withArguments(listOf(
+                        "-xgeneratePluginDebugPluginManifest",
                         "-Pdisable_shadow_transform=true",
                         ":plugin1:PackageMultiPlugin"
                 ))
diff --git a/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageOnlyPluginTest.kt b/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageOnlyPluginTest.kt
index 76f247cc5..750d6d72f 100644
--- a/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageOnlyPluginTest.kt
+++ b/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackageOnlyPluginTest.kt
@@ -46,6 +46,7 @@ class PackageOnlyPluginTest {
                 .withProjectDir(PLUGIN1_PROJECT_DIR)
                 .withPluginClasspath()
                 .withArguments(listOf(
+                        "-xgeneratePluginDebugPluginManifest",
                         "-Pdisable_shadow_transform=true",
                         ":plugin1:packageOnlyApkPlugin"
                 ))
diff --git a/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackagePluginTaskTest.kt b/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackagePluginTaskTest.kt
index ffb80c1d0..cd3e7cf2c 100644
--- a/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackagePluginTaskTest.kt
+++ b/projects/sdk/core/gradle-plugin/src/test/kotlin/com/tencent/shadow/core/gradle/PackagePluginTaskTest.kt
@@ -48,6 +48,7 @@ class PackagePluginTaskTest {
                 .withProjectDir(ROOT_PROJECT_DIR)
                 .withPluginClasspath()
                 .withArguments(listOf(
+                        "-xgeneratePluginDebugPluginManifest",
                         "-Pdisable_shadow_transform=true",
                         ":plugin1:packageDebugPlugin"
                 ))
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/classloaders/PluginClassLoader.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/classloaders/PluginClassLoader.kt
index ea0e76948..4352b5b2f 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/classloaders/PluginClassLoader.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/classloaders/PluginClassLoader.kt
@@ -19,6 +19,7 @@
 package com.tencent.shadow.core.loader.classloaders
 
 import android.os.Build
+import com.tencent.shadow.core.runtime.PluginManifest
 import dalvik.system.BaseDexClassLoader
 import org.jetbrains.annotations.TestOnly
 import java.io.File
@@ -111,6 +112,11 @@ class PluginClassLoader(
         return clazz
     }
 
+    internal fun loadPluginManifest(): PluginManifest {
+        val clazz = findClass("com.tencent.shadow.core.manifest_parser.PluginManifest")
+        return PluginManifest::class.java.cast(clazz.newInstance())
+    }
+
 }
 
 private fun String.subStringBeforeDot() = substringBeforeLast('.', "")
diff --git a/projects/sdk/core/manifest-parser/.gitignore b/projects/sdk/core/manifest-parser/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/projects/sdk/core/manifest-parser/build.gradle b/projects/sdk/core/manifest-parser/build.gradle
new file mode 100644
index 000000000..88d8ae8d0
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/build.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'kotlin'
+
+dependencies {
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    implementation 'com.squareup:javapoet:1.11.1'
+    implementation project(':runtime')
+    testImplementation 'junit:junit:4.12'
+    testImplementation 'commons-io:commons-io:2.9.0'
+    testImplementation 'com.tencent.shadow.coding:java-build-config'
+}
+
+compileKotlin {
+    kotlinOptions {
+        jvmTarget = "1.6"
+    }
+}
+
+compileTestKotlin {
+    kotlinOptions {
+        jvmTarget = "1.6"
+    }
+}
diff --git a/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestKeys.kt b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestKeys.kt
new file mode 100644
index 000000000..3a2e2ad96
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestKeys.kt
@@ -0,0 +1,25 @@
+package com.tencent.shadow.core.manifest_parser
+
+sealed class AndroidManifestKeys {
+    companion object {
+        const val appComponentFactory = "android:appComponentFactory"
+        const val `package` = "package"
+        const val name = "android:name"
+        const val theme = "android:theme"
+        const val configChanges = "android:configChanges"
+        const val windowSoftInputMode = "android:windowSoftInputMode"
+        const val authorities = "android:authorities"
+        const val `intent-filter` = "intent-filter"
+        const val action = "action"
+        const val manifest = "manifest"
+        const val application = "application"
+        const val activity = "activity"
+        const val service = "service"
+        const val provider = "provider"
+        const val receiver = "receiver"
+    }
+}
+typealias ComponentMapKey = String
+typealias ComponentMapValue = Any
+typealias ComponentMap = Map<ComponentMapKey, ComponentMapValue>
+typealias MutableComponentMap = MutableMap<ComponentMapKey, ComponentMapValue>
\ No newline at end of file
diff --git a/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReader.kt b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReader.kt
new file mode 100644
index 000000000..86280b9a7
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReader.kt
@@ -0,0 +1,177 @@
+package com.tencent.shadow.core.manifest_parser
+
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import org.w3c.dom.Node
+import java.io.File
+import javax.xml.parsers.DocumentBuilderFactory
+
+typealias ManifestMap = Map<String, Any>
+
+/**
+ * 读取xml格式的Manifest到内存Map中
+ */
+class AndroidManifestReader {
+    /**
+     * 读取入口方法
+     *
+     * @param xmlFile com.android.build.gradle.tasks.ManifestProcessorTask任务的输出文件，
+     *                一般位于apk工程的build/intermediates/merged_manifest目录中。
+     */
+    fun read(xmlFile: File): ManifestMap {
+        val manifest = readXml(xmlFile).documentElement
+        val application = readApplication(manifest)
+        val globalAttributes = readGlobalAttributes(manifest, application)
+        val components = readComponents(application)
+        return globalAttributes.plus(components)
+    }
+
+    private fun readXml(xmlFile: File): Document {
+        try {
+            val documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance()
+            val documentBuilder = documentBuilderFactory.newDocumentBuilder()
+            return documentBuilder.parse(xmlFile)!!
+        } catch (e: Exception) {
+            throw RuntimeException("xml应该是AGP生成的合法文件，所以不兼容任何xml读取错误", e)
+        }
+    }
+
+    private fun readApplication(manifest: Element): Element? {
+        val elements = manifest.getElementsByTagName(AndroidManifestKeys.application)
+        return if (elements.length == 1) {
+            val node = elements.item(0)
+            assert(node.nodeType == Node.ELEMENT_NODE)
+            elements.item(0) as Element
+        } else {
+            null
+        }
+    }
+
+    /**
+     * 读取Manifest中那些唯一的属性
+     */
+    private fun readGlobalAttributes(manifest: Element, application: Element?): Map<String, Any> {
+        val globalAttributes = mutableMapOf<String, Any>()
+
+        fun manifestAttribute(name: String) {
+            globalAttributes[name] = manifest.getAttribute(name)
+        }
+
+        fun applicationAttribute(name: String) {
+            if (application != null) {
+                val attribute = application.getAttribute(name)
+                if (attribute.isNotEmpty()) {
+                    globalAttributes[name] = attribute
+                }
+            }
+        }
+
+        manifestAttribute(AndroidManifestKeys.`package`)
+        listOf(
+                AndroidManifestKeys.name,
+                AndroidManifestKeys.theme,
+                AndroidManifestKeys.appComponentFactory,
+        ).forEach(::applicationAttribute)
+        return globalAttributes
+    }
+
+    private fun readComponents(application: Element?) =
+            listOf(
+                    AndroidManifestKeys.activity to ::parseActivity,
+                    AndroidManifestKeys.service to ::parseService,
+                    AndroidManifestKeys.receiver to ::parseReceiver,
+                    AndroidManifestKeys.provider to ::parseProvider,
+            ).map { (componentKey, parseMethod) ->
+                val componentArray = parseComponents(application, componentKey, parseMethod)
+                componentKey to componentArray
+            }
+
+
+    private fun parseComponents(
+            application: Element?,
+            componentKey: String,
+            parseFunction: (Element) -> ComponentMap
+    ): Array<ComponentMap> {
+        if (application == null) {
+            return emptyArray()
+        }
+        val nodeList = application.getElementsByTagName(componentKey)
+        val length = nodeList.length
+        val collectionList = mutableListOf<ComponentMap>()
+        for (i in 0 until length) {
+            val node = nodeList.item(i)
+            assert(node.nodeType == Node.ELEMENT_NODE)
+            val map = parseFunction(node as Element)
+            collectionList.add(map)
+        }
+        return collectionList.toTypedArray()
+    }
+
+    private fun parseActivity(element: Element): ComponentMap {
+        val activityMap = parseComponent(element).toMutableMap()
+
+        listOf(
+                AndroidManifestKeys.theme,
+                AndroidManifestKeys.configChanges,
+                AndroidManifestKeys.windowSoftInputMode,
+        ).forEach { attributeKey ->
+            activityMap.putAttributeIfNotNull(element, attributeKey)
+        }
+        return activityMap
+    }
+
+    private fun parseService(element: Element): ComponentMap {
+        return parseComponent(element)
+    }
+
+    private fun parseReceiver(element: Element): ComponentMap {
+        val receiverMap = parseComponent(element).toMutableMap()
+
+        val receiverActions = parseReceiverActions(element)
+        if (receiverActions.isNotEmpty()) {
+            receiverMap[AndroidManifestKeys.action] = receiverActions
+        }
+
+        return receiverMap
+    }
+
+    private fun parseReceiverActions(receiverElement: Element): List<String> {
+        val intentFilters = receiverElement.getElementsByTagName(AndroidManifestKeys.`intent-filter`)
+        val collectionList = mutableListOf<String>()
+        for (i in 0 until intentFilters.length) {
+            val intentFilter = intentFilters.item(i)
+            assert(intentFilter.nodeType == Node.ELEMENT_NODE)
+            val actions = (intentFilter as Element).getElementsByTagName(AndroidManifestKeys.action)
+            for (j in 0 until actions.length) {
+                val action = actions.item(j)
+                assert(action.nodeType == Node.ELEMENT_NODE)
+                val actionName = (action as Element).getAttribute(AndroidManifestKeys.name)
+                collectionList.add(actionName)
+            }
+        }
+        return collectionList
+    }
+
+    private fun parseProvider(element: Element): ComponentMap {
+        val providerMap = parseComponent(element).toMutableMap()
+
+        providerMap.putAttributeIfNotNull(element, AndroidManifestKeys.authorities)
+
+        return providerMap
+    }
+
+    private fun parseComponent(element: Element): ComponentMap {
+        val componentName = element.getAttribute(AndroidManifestKeys.name)
+        return mapOf(
+                AndroidManifestKeys.name to componentName
+        )
+    }
+
+    private fun MutableComponentMap.putAttributeIfNotNull(
+            componentElement: Element,
+            attributeKey: String) {
+        if (componentElement.hasAttribute(attributeKey)) {
+            this[attributeKey] = componentElement.getAttribute(attributeKey)
+        }
+    }
+}
diff --git a/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/ManifestParser.kt b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/ManifestParser.kt
new file mode 100644
index 000000000..584a1952f
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/ManifestParser.kt
@@ -0,0 +1,18 @@
+package com.tencent.shadow.core.manifest_parser
+
+import java.io.File
+
+/**
+ * manifest-parser的入口方法
+ *
+ * @param xmlFile       com.android.build.gradle.tasks.ManifestProcessorTask任务的输出文件，
+ *                      一般位于apk工程的build/intermediates/merged_manifest目录中。
+ * @param outputDir     生成文件的输出目录
+ * @param packageName   生成类的包名
+ * @param packageForR   生成对R.java引用时需要的R文件的包名
+ */
+fun generatePluginManifest(xmlFile: File, outputDir: File, packageName: String, packageForR: String) {
+    val androidManifest = AndroidManifestReader().read(xmlFile)
+    val generator = PluginManifestGenerator(packageForR)
+    generator.generate(androidManifest, outputDir, packageName)
+}
\ No newline at end of file
diff --git a/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGenerator.kt b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGenerator.kt
new file mode 100644
index 000000000..1c6a93b3a
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGenerator.kt
@@ -0,0 +1,361 @@
+package com.tencent.shadow.core.manifest_parser
+
+import com.squareup.javapoet.*
+import com.tencent.shadow.core.runtime.PluginManifest
+import java.io.File
+import java.util.*
+import javax.lang.model.element.Modifier
+
+/**
+ * PluginManifest.java生成器
+ *
+ * 将Loader所需的插件Manifest信息生成为Java文件，
+ * 添加runtime中PluginManifest接口的实现方法
+ *
+ * @param packageForR 生成对R.java引用时需要的R文件的包名
+ */
+class PluginManifestGenerator(private val packageForR: String) {
+    /**
+     * 生成器入口方法
+     *
+     * 根据AndroidManifestReader输出的Map生成PluginManifest.java到outputDir目录中。
+     *
+     * @param manifestMap   AndroidManifestReader#read的输出Map
+     * @param outputDir     生成文件的输出目录
+     * @param packageName   生成类的包名
+     */
+    fun generate(manifestMap: ManifestMap, outputDir: File, packageName: String) {
+        val pluginManifestBuilder = PluginManifestBuilder(manifestMap, packageForR)
+        val pluginManifest = pluginManifestBuilder.build()
+        JavaFile.builder(packageName, pluginManifest)
+                .build()
+                .writeTo(outputDir)
+    }
+}
+
+private class PluginManifestBuilder(
+        val manifestMap: ManifestMap,
+        val packageForR: String
+) {
+    val classBuilder: TypeSpec.Builder =
+            TypeSpec.classBuilder("PluginManifest")
+                    .addSuperinterface(ClassName.get(PluginManifest::class.java))
+                    .addModifiers(Modifier.PUBLIC)!!
+
+    fun build(): TypeSpec {
+        listOf(
+                *buildApplicationFields(),
+                buildActivityInfoArrayField(),
+                buildServiceInfoArrayField(),
+                buildReceiverInfoArrayField(),
+                buildProviderInfoArrayField(),
+        ).forEach { fieldSpec ->
+            val getterMethod = buildGetterMethod(fieldSpec)
+            classBuilder.addField(fieldSpec)
+            classBuilder.addMethod(getterMethod)
+        }
+        return classBuilder.build()
+    }
+
+    private fun buildApplicationFields(): Array<FieldSpec> {
+        val stringFields = mapOf(
+                "applicationPackageName" to AndroidManifestKeys.`package`,
+                "applicationClassName" to AndroidManifestKeys.name,
+                "appComponentFactory" to AndroidManifestKeys.appComponentFactory,
+        ).map { (fieldName, key) ->
+            buildStringField(fieldName, key)
+        }
+
+        val resIdFields = mapOf(
+                "applicationTheme" to AndroidManifestKeys.theme,
+        ).map { (fieldName, key) ->
+            buildResIdField(fieldName, key)
+        }
+
+        return (stringFields + resIdFields).toTypedArray()
+    }
+
+    private fun buildActivityInfoArrayField() = buildComponentArrayField(
+            AndroidManifestKeys.activity,
+            "ActivityInfo",
+            "activities",
+            ::toNewActivityInfo,
+    )
+
+    private fun buildServiceInfoArrayField() = buildComponentArrayField(
+            AndroidManifestKeys.service,
+            "ServiceInfo",
+            "services",
+            ::toNewServiceInfo,
+    )
+
+    private fun buildReceiverInfoArrayField() = buildComponentArrayField(
+            AndroidManifestKeys.receiver,
+            "ReceiverInfo",
+            "receivers",
+            ::toNewReceiverInfo,
+    )
+
+    private fun buildProviderInfoArrayField() = buildComponentArrayField(
+            AndroidManifestKeys.provider,
+            "ProviderInfo",
+            "providers",
+            ::toNewProviderInfo,
+    )
+
+    private fun buildComponentArrayField(
+            key: String,
+            subClassName: String,
+            fieldName: String,
+            transform: (ComponentMap) -> String
+    ): FieldSpec {
+        @Suppress("UNCHECKED_CAST")
+        val componentMapArray = manifestMap[key] as Array<ComponentMap>
+        val literal = componentMapArray.joinToString(
+                separator = ",\n",
+                prefix = "{\n",
+                postfix = "\n}",
+                transform = transform
+        )
+
+        val componentInfoArrayTypeName = ArrayTypeName.of(ClassName.get(
+                "com.tencent.shadow.core.runtime",
+                "PluginManifest",
+                subClassName))
+
+        val codeBlock = if (componentMapArray.isNotEmpty()) {
+            CodeBlock.of("new \$1T \$2L", componentInfoArrayTypeName, literal)
+        } else {
+            nullCodeBlock()
+        }
+        return privateStaticFinalFieldBuilder(
+                componentInfoArrayTypeName,
+                fieldName,
+        ).initializer(
+                codeBlock
+        ).build()
+    }
+
+    private fun buildStringField(fieldName: String, key: String): FieldSpec {
+        val value = manifestMap[key]
+        val codeBlock = if (value != null) {
+            CodeBlock.of("\"$1L\"", value)
+        } else {
+            nullCodeBlock()
+        }
+        return privateStaticFinalStringFieldBuilder(fieldName)
+                .initializer(codeBlock).build()
+    }
+
+    private fun buildGetterMethod(fieldSpec: FieldSpec): MethodSpec =
+            MethodSpec.methodBuilder("get${fieldSpec.name.capitalize()}")
+                    .addModifiers(
+                            Modifier.PUBLIC,
+                            Modifier.FINAL,
+                    )
+                    .returns(fieldSpec.type)
+                    .addStatement(CodeBlock.of("return ${fieldSpec.name}"))
+                    .build()
+
+    private fun buildResIdField(fieldName: String, key: String): FieldSpec {
+        val manifestValue = manifestMap[key]
+        return if (manifestValue != null) {
+            buildResIdFieldWithValue(fieldName, manifestValue)
+        } else {
+            privateStaticFinalIntFieldBuilder(fieldName)
+                    .initializer(
+                            CodeBlock.of("$1L", "0")
+                    ).build()
+        }
+    }
+
+    private fun buildResIdFieldWithValue(
+            fieldName: String,
+            manifestValue: Any,
+    ): FieldSpec {
+
+        val resIdLiteral = themeStringToResId(manifestValue, packageForR)
+        return privateStaticFinalIntFieldBuilder(fieldName)
+                .initializer(
+                        CodeBlock.of("$1L", resIdLiteral)
+                ).build()
+    }
+
+
+    private fun toNewActivityInfo(componentMap: ComponentMap): String {
+        fun makeResIdLiteral(key: String,
+                             valueToResId: (value: String) -> String): String {
+            val value = componentMap[key] as String?
+            val literal = if (value != null) {
+                valueToResId(value)
+            } else {
+                "0"
+            }
+            return literal
+        }
+
+        val themeLiteral = makeResIdLiteral(AndroidManifestKeys.theme) {
+            themeStringToResId(it, packageForR)
+        }
+        val configChangesLiteral = makeResIdLiteral(AndroidManifestKeys.configChanges) {
+            configChangesToInt(it)
+        }
+        val softInputModeLiteral = makeResIdLiteral(AndroidManifestKeys.windowSoftInputMode) {
+            windowSoftInputModeToInt(it)
+        }
+
+        return "new com.tencent.shadow.core.runtime.PluginManifest" +
+                ".ActivityInfo(" +
+                "\"${componentMap[AndroidManifestKeys.name]}\", " +
+                "$themeLiteral ," +
+                "$configChangesLiteral ," +
+                softInputModeLiteral +
+                ")"
+    }
+
+    private fun toNewServiceInfo(componentMap: ComponentMap): String {
+        return "new com.tencent.shadow.core.runtime.PluginManifest" +
+                ".ServiceInfo(\"${componentMap[AndroidManifestKeys.name]}\")"
+    }
+
+    private fun toNewReceiverInfo(componentMap: ComponentMap): String {
+        @Suppress("UNCHECKED_CAST")
+        val actions = componentMap[AndroidManifestKeys.action] as List<String>?
+        val actionsLiteral =
+                actions?.joinToString(
+                        prefix = "new String[]{\"",
+                        separator = "\", \"",
+                        postfix = "\"}"
+                ) ?: "null"
+
+        return "new com.tencent.shadow.core.runtime.PluginManifest" +
+                ".ReceiverInfo(\"${componentMap[AndroidManifestKeys.name]}\", " +
+                actionsLiteral +
+                ")"
+    }
+
+    private fun toNewProviderInfo(componentMap: ComponentMap): String {
+        val authoritiesValue = componentMap[AndroidManifestKeys.authorities]
+        val authoritiesLiteral =
+                if (authoritiesValue != null) {
+                    "\"${authoritiesValue}\""
+                } else {
+                    "null"
+                }
+
+        return "new com.tencent.shadow.core.runtime.PluginManifest" +
+                ".ProviderInfo(\"${componentMap[AndroidManifestKeys.name]}\", $authoritiesLiteral)"
+    }
+
+    companion object {
+        fun privateStaticFinalFieldBuilder(type: TypeName, fieldName: String) = FieldSpec.builder(
+                type,
+                fieldName,
+                Modifier.PRIVATE,
+                Modifier.STATIC,
+                Modifier.FINAL,
+        )!!
+
+        fun privateStaticFinalStringFieldBuilder(fieldName: String) =
+                privateStaticFinalFieldBuilder(
+                        ClassName.get(String::class.java),
+                        fieldName,
+                )
+
+        fun privateStaticFinalIntFieldBuilder(fieldName: String) =
+                privateStaticFinalFieldBuilder(
+                        TypeName.INT,
+                        fieldName,
+                )
+
+        fun nullCodeBlock() = CodeBlock.of("null")!!
+
+        fun themeStringToResId(manifestValue: Any, packageForR: String): String {
+            val resName = manifestValue as String // for example: @style/TestPluginTheme
+            val split = resName.split('/')
+            val packagePart = split[0] // for example: @style
+            val namePart = split[1] // for example: TestPluginTheme
+
+            val isSystemResource = packagePart.startsWith("@android:")
+            val packageNameOfRClass = if (isSystemResource) {
+                "android"
+            } else {
+                packageForR
+            }
+
+            val innerClassName = if (isSystemResource) { // for example: style
+                packagePart.removePrefix("@android:")
+            } else {
+                packagePart.removePrefix("@")
+            }
+
+            val resIdFieldName = namePart.replace('.', '_')
+            return "${packageNameOfRClass}.R.${innerClassName}.${resIdFieldName}"
+        }
+
+        private fun flagsToInt(
+                stringValue: String,
+                className: String,
+                fieldMap: (String) -> String,
+        ): String =
+                stringValue.split('|')
+                        .map(String::trim)
+                        .map(fieldMap)
+                        .map { "${className}.${it}" }
+                        .reduce { acc, i -> "$acc|$i" }
+
+        private fun configChangesToInt(configChangesValue: String): String =
+                flagsToInt(
+                        configChangesValue,
+                        "android.content.pm.ActivityInfo"
+                ) {
+                    when (it) {
+                        "mcc" -> "CONFIG_MCC"
+                        "mnc" -> "CONFIG_MNC"
+                        "locale" -> "CONFIG_LOCALE"
+                        "touchscreen" -> "CONFIG_TOUCHSCREEN"
+                        "keyboard" -> "CONFIG_KEYBOARD"
+                        "keyboardHidden" -> "CONFIG_KEYBOARD_HIDDEN"
+                        "navigation" -> "CONFIG_NAVIGATION"
+                        "orientation" -> "CONFIG_ORIENTATION"
+                        "screenLayout" -> "CONFIG_SCREEN_LAYOUT"
+                        "uiMode" -> "CONFIG_UI_MODE"
+                        "screenSize" -> "CONFIG_SCREEN_SIZE"
+                        "smallestScreenSize" -> "CONFIG_SMALLEST_SCREEN_SIZE"
+                        "density" -> "CONFIG_DENSITY"
+                        "layoutDirection" -> "CONFIG_LAYOUT_DIRECTION"
+                        "colorMode" -> "CONFIG_COLOR_MODE"
+                        "assetsPaths" -> "CONFIG_ASSETS_PATHS"
+                        "fontScale" -> "CONFIG_FONT_SCALE"
+                        "windowConfiguration" -> "CONFIG_WINDOW_CONFIGURATION"
+                        else -> throw IllegalArgumentException("不认识$it")
+                    }
+                }
+
+        private fun windowSoftInputModeToInt(windowSoftInputModeValue: String): String =
+                flagsToInt(
+                        windowSoftInputModeValue,
+                        "android.view.WindowManager.LayoutParams"
+                ) {
+                    when (it) {
+                        "stateUnspecified" -> "SOFT_INPUT_STATE_UNSPECIFIED"
+                        "stateUnchanged" -> "SOFT_INPUT_STATE_UNCHANGED"
+                        "stateHidden" -> "SOFT_INPUT_STATE_HIDDEN"
+                        "stateAlwaysHidden" -> "SOFT_INPUT_STATE_ALWAYS_HIDDEN"
+                        "stateVisible" -> "SOFT_INPUT_STATE_VISIBLE"
+                        "stateAlwaysVisible" -> "SOFT_INPUT_STATE_ALWAYS_VISIBLE"
+                        "adjustUnspecified" -> "SOFT_INPUT_ADJUST_UNSPECIFIED"
+                        "adjustResize" -> "SOFT_INPUT_ADJUST_RESIZE"
+                        "adjustPan" -> "SOFT_INPUT_ADJUST_PAN"
+                        "adjustNothing" -> "SOFT_INPUT_ADJUST_NOTHING"
+                        "isForwardNavigation" -> "SOFT_INPUT_IS_FORWARD_NAVIGATION"
+                        else -> throw IllegalArgumentException("不认识$it")
+                    }
+                }
+
+        private fun String.capitalize() =
+                replaceFirstChar {
+                    if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
+                }
+    }
+}
diff --git a/projects/sdk/core/manifest-parser/src/test/java/android/R.java b/projects/sdk/core/manifest-parser/src/test/java/android/R.java
new file mode 100644
index 000000000..71954adcf
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/java/android/R.java
@@ -0,0 +1,7 @@
+package android;
+
+public final class R {
+    public static final class style {
+        public static final int Theme_NoTitleBar = 0x01030006;
+    }
+}
diff --git a/projects/sdk/core/manifest-parser/src/test/java/android/content/pm/ActivityInfo.java b/projects/sdk/core/manifest-parser/src/test/java/android/content/pm/ActivityInfo.java
new file mode 100644
index 000000000..feade0592
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/java/android/content/pm/ActivityInfo.java
@@ -0,0 +1,42 @@
+package android.content.pm;
+
+/**
+ * mock for test
+ */
+public interface ActivityInfo {
+    int CONFIG_MCC = 0x0001;
+
+    int CONFIG_MNC = 0x0002;
+
+    int CONFIG_LOCALE = 0x0004;
+
+    int CONFIG_TOUCHSCREEN = 0x0008;
+
+    int CONFIG_KEYBOARD = 0x0010;
+
+    int CONFIG_KEYBOARD_HIDDEN = 0x0020;
+
+    int CONFIG_NAVIGATION = 0x0040;
+
+    int CONFIG_ORIENTATION = 0x0080;
+
+    int CONFIG_SCREEN_LAYOUT = 0x0100;
+
+    int CONFIG_UI_MODE = 0x0200;
+
+    int CONFIG_SCREEN_SIZE = 0x0400;
+
+    int CONFIG_SMALLEST_SCREEN_SIZE = 0x0800;
+
+    int CONFIG_DENSITY = 0x1000;
+
+    int CONFIG_LAYOUT_DIRECTION = 0x2000;
+
+    int CONFIG_COLOR_MODE = 0x4000;
+
+    int CONFIG_ASSETS_PATHS = 0x80000000;
+
+    int CONFIG_FONT_SCALE = 0x40000000;
+
+    int CONFIG_WINDOW_CONFIGURATION = 0x20000000;
+}
diff --git a/projects/sdk/core/manifest-parser/src/test/java/android/view/WindowManager.java b/projects/sdk/core/manifest-parser/src/test/java/android/view/WindowManager.java
new file mode 100644
index 000000000..3e5686e33
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/java/android/view/WindowManager.java
@@ -0,0 +1,21 @@
+package android.view;
+
+/**
+ * mock for test
+ */
+public interface WindowManager {
+    interface LayoutParams {
+        int SOFT_INPUT_STATE_UNSPECIFIED = 0;
+        int SOFT_INPUT_STATE_UNCHANGED = 1;
+        int SOFT_INPUT_STATE_HIDDEN = 2;
+        int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
+        int SOFT_INPUT_STATE_VISIBLE = 4;
+        int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
+        int SOFT_INPUT_MASK_ADJUST = 0xf0;
+        int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
+        int SOFT_INPUT_ADJUST_RESIZE = 0x10;
+        int SOFT_INPUT_ADJUST_PAN = 0x20;
+        int SOFT_INPUT_ADJUST_NOTHING = 0x30;
+        int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
+    }
+}
diff --git a/projects/sdk/core/manifest-parser/src/test/java/com/tencent/shadow/sample/plugin/app/lib/R.java b/projects/sdk/core/manifest-parser/src/test/java/com/tencent/shadow/sample/plugin/app/lib/R.java
new file mode 100644
index 000000000..9780277ca
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/java/com/tencent/shadow/sample/plugin/app/lib/R.java
@@ -0,0 +1,7 @@
+package com.tencent.shadow.sample.plugin.app.lib;
+
+public final class R {
+    public static final class style {
+        public static final int TestPluginTheme = 0x7f030001;
+    }
+}
diff --git a/projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReaderTest.kt b/projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReaderTest.kt
new file mode 100644
index 000000000..6c87e61f5
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReaderTest.kt
@@ -0,0 +1,17 @@
+package com.tencent.shadow.core.manifest_parser
+
+import org.junit.Assert
+import org.junit.Test
+import java.io.File
+
+class AndroidManifestReaderTest {
+    @Test
+    fun testReadXml() {
+        val testFile = File(javaClass.classLoader.getResource("sample-app.xml")!!.toURI())
+        val androidManifest = AndroidManifestReader().read(testFile)
+        Assert.assertEquals("com.tencent.shadow.sample.host", androidManifest[AndroidManifestKeys.`package`])
+        Assert.assertEquals("com.tencent.shadow.sample.plugin.app.lib.UseCaseApplication", androidManifest[AndroidManifestKeys.name])
+        Assert.assertEquals("com.tencent.shadow.test.plugin.androidx_cases.lib.TestComponentFactory", androidManifest[AndroidManifestKeys.appComponentFactory])
+        Assert.assertEquals("@android:style/Theme.NoTitleBar", androidManifest[AndroidManifestKeys.theme])
+    }
+}
\ No newline at end of file
diff --git a/projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGeneratorTest.kt b/projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGeneratorTest.kt
new file mode 100644
index 000000000..f1795e39c
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGeneratorTest.kt
@@ -0,0 +1,40 @@
+package com.tencent.shadow.core.manifest_parser
+
+import org.junit.Assert
+import org.junit.Test
+import java.io.File
+
+class PluginManifestGeneratorTest {
+
+    @Test
+    fun testCompileCaseAsLittleAsPossible() {
+        testCompile("case_as_little_as_possible.xml", "")
+    }
+
+    @Test
+    fun testNoAppComponentFactory() {
+        testCompile("noAppComponentFactory.xml", "")
+    }
+
+    @Test
+    fun testCompileSampleApp() {
+        testCompile("sample-app.xml", "com.tencent.shadow.sample.plugin.app.lib")
+    }
+
+    private fun testCompile(case: String, packageForR: String) {
+        val testFile = File(javaClass.classLoader.getResource(case)!!.toURI())
+        val androidManifest = AndroidManifestReader().read(testFile)
+        val generator = PluginManifestGenerator(packageForR)
+
+        val tempBuildDir = File("build", "PluginManifestGeneratorTest")
+        val outputDir = File(tempBuildDir, case)
+        println("outputDir==$outputDir")
+        generator.generate(androidManifest, outputDir, "test")
+
+        val cmd = "javac -cp ../runtime/build/classes/java/main:build/classes/java/test" +
+                " ${outputDir.absolutePath}/test/PluginManifest.java"
+        val process = Runtime.getRuntime().exec(cmd)
+        val ret = process.waitFor()
+        Assert.assertEquals(cmd, 0, ret)
+    }
+}
\ No newline at end of file
diff --git a/projects/sdk/core/manifest-parser/src/test/resources/case_as_little_as_possible.xml b/projects/sdk/core/manifest-parser/src/test/resources/case_as_little_as_possible.xml
new file mode 100644
index 000000000..b5308d2f4
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/resources/case_as_little_as_possible.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.tencent.shadow.test.hostapp" android:versionCode="1" android:versionName="local">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
+
+</manifest>
\ No newline at end of file
diff --git a/projects/sdk/core/manifest-parser/src/test/resources/noAppComponentFactory.xml b/projects/sdk/core/manifest-parser/src/test/resources/noAppComponentFactory.xml
new file mode 100644
index 000000000..f5b0162c2
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/resources/noAppComponentFactory.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.tencent.shadow.test.hostapp" android:versionCode="1" android:versionName="local">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
+    <application android:name="com.tencent.shadow.sample.plugin.app.lib.UseCaseApplication" />
+</manifest>
\ No newline at end of file
diff --git a/projects/sdk/core/manifest-parser/src/test/resources/sample-app.xml b/projects/sdk/core/manifest-parser/src/test/resources/sample-app.xml
new file mode 100644
index 000000000..ac4789f54
--- /dev/null
+++ b/projects/sdk/core/manifest-parser/src/test/resources/sample-app.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1"
+    android:versionName="local" package="com.tencent.shadow.sample.host">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
+
+    <uses-feature android:glEsVersion="0x00020000" />
+
+    <application android:debuggable="true" android:icon="@android:drawable/sym_def_app_icon"
+        android:label="@string/app_name"
+        android:name="com.tencent.shadow.sample.plugin.app.lib.UseCaseApplication"
+        android:appComponentFactory="com.tencent.shadow.test.plugin.androidx_cases.lib.TestComponentFactory"
+        android:theme="@android:style/Theme.NoTitleBar">
+
+        <meta-data android:name="test_meta" android:value="test_value" />
+
+        <activity android:theme="@style/TestPluginTheme"
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivityReCreate" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivitySetTheme" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivityOptionMenu" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivityOnCreate" />
+
+        <activity android:configChanges="orientation|screenSize|fontScale"
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivityOrientation"
+            android:windowSoftInputMode="adjustResize" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivityWindowSoftMode"
+            android:windowSoftInputMode="stateVisible" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestDBContentProviderActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.activity.TestActivityReCreateBySystem" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.receiver.TestReceiverActivity"
+            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.receiver.TestDynamicReceiverActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestDynamicFragmentActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestXmlFragmentActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.dialog.TestDialogActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.packagemanager.TestPackageManagerActivity" />
+
+        <receiver
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.receiver.MyReceiver">
+
+            <intent-filter>
+
+                <action android:name="com.tencent.test.action" />
+
+            </intent-filter>
+            />
+        </receiver>
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestFileProviderActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.application.TestApplicationActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.context.ActivityContextSubDirTestActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.context.ApplicationContextSubDirTestActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.host_communication.PluginUseHostClassActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.webview.WebViewActivity" />
+
+        <activity
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestDialogFragmentActivity" />
+
+        <provider android:authorities="com.tencent.shadow.sample.host.provider.test"
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestProvider" />
+
+        <service
+            android:name="com.tencent.shadow.sample.plugin.app.lib.usecases.service.HostAddPluginViewService" />
+
+    </application>
+
+</manifest>
diff --git a/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PluginManifest.java b/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PluginManifest.java
new file mode 100644
index 000000000..a4bfb5972
--- /dev/null
+++ b/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PluginManifest.java
@@ -0,0 +1,142 @@
+package com.tencent.shadow.core.runtime;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public interface PluginManifest {
+    /**
+     * same as android.content.pm.PackageItemInfo#packageName
+     */
+    String getApplicationPackageName();
+
+    /**
+     * same as android.content.pm.ApplicationInfo#className
+     */
+    String getApplicationClassName();
+
+    /**
+     * same as android.content.pm.ApplicationInfo#appComponentFactory
+     */
+    String getAppComponentFactory();
+
+    /**
+     * same as android.content.pm.ApplicationInfo#theme
+     */
+    int getApplicationTheme();
+
+    ActivityInfo[] getActivities();
+
+    ServiceInfo[] getServices();
+
+    ReceiverInfo[] getReceivers();
+
+    ProviderInfo[] getProviders();
+
+    abstract class ComponentInfo implements Parcelable {
+        public final String className;
+
+        public ComponentInfo(String className) {
+            this.className = className;
+        }
+
+        protected ComponentInfo(Parcel in) {
+            className = in.readString();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(className);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<ComponentInfo> CREATOR = new Creator<ComponentInfo>() {
+            @Override
+            public ComponentInfo createFromParcel(Parcel in) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public ComponentInfo[] newArray(int size) {
+                return new ComponentInfo[size];
+            }
+        };
+    }
+
+    final class ActivityInfo extends ComponentInfo implements Parcelable {
+        public final int theme;
+        public final int configChanges;
+        public final int softInputMode;
+
+        public ActivityInfo(String className,
+                            int theme,
+                            int configChanges,
+                            int softInputMode) {
+            super(className);
+            this.theme = theme;
+            this.configChanges = configChanges;
+            this.softInputMode = softInputMode;
+        }
+
+        protected ActivityInfo(Parcel in) {
+            super(in);
+            theme = in.readInt();
+            configChanges = in.readInt();
+            softInputMode = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(theme);
+            dest.writeInt(configChanges);
+            dest.writeInt(softInputMode);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<ActivityInfo> CREATOR = new Creator<ActivityInfo>() {
+            @Override
+            public ActivityInfo createFromParcel(Parcel in) {
+                return new ActivityInfo(in);
+            }
+
+            @Override
+            public ActivityInfo[] newArray(int size) {
+                return new ActivityInfo[size];
+            }
+        };
+    }
+
+    final class ServiceInfo extends ComponentInfo {
+
+        public ServiceInfo(String className) {
+            super(className);
+        }
+    }
+
+    final class ReceiverInfo extends ComponentInfo {
+        public final String[] actions;
+
+        public ReceiverInfo(String className, String[] actions) {
+            super(className);
+            this.actions = actions;
+        }
+    }
+
+    final class ProviderInfo extends ComponentInfo {
+        public final String authorities;
+
+        public ProviderInfo(String className, String authorities) {
+            super(className);
+            this.authorities = authorities;
+        }
+    }
+
+}
diff --git a/projects/sdk/core/settings.gradle b/projects/sdk/core/settings.gradle
index cfcdf1214..b36ae5451 100644
--- a/projects/sdk/core/settings.gradle
+++ b/projects/sdk/core/settings.gradle
@@ -7,6 +7,7 @@ include 'loader',
         'common',
         'manager',
         'manager-db-test',
+        'manifest-parser',
         'load-parameters',
         'transform-kit',
         'utils'
\ No newline at end of file
diff --git a/projects/test/plugin/androidx-cases/test-plugin-androidx-cases/build.gradle b/projects/test/plugin/androidx-cases/test-plugin-androidx-cases/build.gradle
index d2ff1bd4c..e09ae67a7 100644
--- a/projects/test/plugin/androidx-cases/test-plugin-androidx-cases/build.gradle
+++ b/projects/test/plugin/androidx-cases/test-plugin-androidx-cases/build.gradle
@@ -41,6 +41,10 @@ dependencies {
 
     implementation "androidx.activity:activity:$activity_version"
     implementation "androidx.appcompat:appcompat:$appcompat_version"
+
+    //Shadow Transform后业务代码会有一部分实际引用runtime中的类
+    //如果不以compileOnly方式依赖，会导致其他Transform或者Proguard找不到这些类
+    pluginCompileOnly 'com.tencent.shadow.core:runtime'
 }
 
 buildscript {
diff --git a/projects/test/plugin/general-cases/test-plugin-general-cases/build.gradle b/projects/test/plugin/general-cases/test-plugin-general-cases/build.gradle
index b90858c0c..9c0de39bf 100644
--- a/projects/test/plugin/general-cases/test-plugin-general-cases/build.gradle
+++ b/projects/test/plugin/general-cases/test-plugin-general-cases/build.gradle
@@ -49,6 +49,10 @@ dependencies {
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
     androidTestImplementation 'androidx.test.espresso:espresso-remote:3.3.0'
     androidTestImplementation "androidx.test:runner:1.3.0"
+
+    //Shadow Transform后业务代码会有一部分实际引用runtime中的类
+    //如果不以compileOnly方式依赖，会导致其他Transform或者Proguard找不到这些类
+    pluginCompileOnly 'com.tencent.shadow.core:runtime'
 }
 
 buildscript {
diff --git a/projects/test/plugin/particular-cases/plugin-service-for-host/build.gradle b/projects/test/plugin/particular-cases/plugin-service-for-host/build.gradle
index e28968788..96ffb3eca 100644
--- a/projects/test/plugin/particular-cases/plugin-service-for-host/build.gradle
+++ b/projects/test/plugin/particular-cases/plugin-service-for-host/build.gradle
@@ -34,6 +34,12 @@ android {
     }
 }
 
+dependencies {
+    //Shadow Transform后业务代码会有一部分实际引用runtime中的类
+    //如果不以compileOnly方式依赖，会导致其他Transform或者Proguard找不到这些类
+    pluginCompileOnly 'com.tencent.shadow.core:runtime'
+}
+
 buildscript {
     repositories {
         if (!System.getenv().containsKey("DISABLE_TENCENT_MAVEN_MIRROR")) {

From 73974f6774f23996f2707aaab87496f6f880de48 Mon Sep 17 00:00:00 2001
From: shifujun <shifujun@foxmail.com>
Date: Fri, 24 Dec 2021 17:00:27 +0800
Subject: [PATCH 2/2] =?UTF-8?q?perf(core):=20=E5=8E=BB=E9=99=A4=E5=8A=A0?=
 =?UTF-8?q?=E8=BD=BD=E6=8F=92=E4=BB=B6=E5=AF=B9getPackageArchiveInfo?=
 =?UTF-8?q?=E7=9A=84=E4=BE=9D=E8=B5=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

由于PackageManager.getPackageArchiveInfo方法在解析较大的Manifest时速度很慢，
而且加载插件过程中只依赖很少量的字段，如className，theme等，所以在主路径不再依赖它，
而是依赖编译期生成好的PluginManifest类。

另一原因是getPackageArchiveInfo的返回类型没有公开API告诉我们Receiver的action字段。

在插件代码主动通过PackageManager获取信息时，再依赖getPackageArchiveInfo方法
获取MetaData等插件框架本身不需要的信息。

close #696
---
 .../shadow/core/loader/ShadowPluginLoader.kt  |  14 --
 ...uginApkBloc.kt => CheckPackageNameBloc.kt} |  67 +-----
 .../loader/blocs/CreateApplicationBloc.kt     |  26 +--
 .../blocs/CreatePluginApplicationInfoBloc.kt  |  43 ++++
 .../core/loader/blocs/CreateResourceBloc.kt   |  15 +-
 .../core/loader/blocs/LoadPluginBloc.kt       | 102 ++++------
 .../core/loader/blocs/ParseManifestBloc.kt    |  90 ---------
 .../delegates/ShadowActivityDelegate.kt       |  24 ++-
 .../delegates/ShadowNativeActivityDelegate.kt |   5 +-
 .../shadow/core/loader/infos/ManifestInfo.kt  |  28 ---
 .../core/loader/infos/PluginActivityInfo.kt   |  51 -----
 .../core/loader/infos/PluginComponentInfo.kt  |  23 ---
 .../shadow/core/loader/infos/PluginInfo.kt    |  57 ------
 .../shadow/core/loader/infos/PluginParts.kt   |   1 -
 .../core/loader/infos/PluginProviderInfo.kt   |  51 -----
 .../core/loader/infos/PluginReceiverInfo.kt   |  42 ----
 .../core/loader/infos/PluginServiceInfo.kt    |  48 -----
 .../core/loader/managers/ComponentManager.kt  | 119 ++++++++---
 .../managers/PluginContentProviderManager.kt  |  29 ++-
 .../managers/PluginPackageManagerImpl.kt      | 190 ++++++++++--------
 .../runtime/PackageManagerInvokeRedirect.java |   2 +-
 .../core/runtime/ShadowApplication.java       |  12 +-
 22 files changed, 357 insertions(+), 682 deletions(-)
 rename projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/{ParsePluginApkBloc.kt => CheckPackageNameBloc.kt} (54%)
 create mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreatePluginApplicationInfoBloc.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParseManifestBloc.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/ManifestInfo.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginActivityInfo.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginComponentInfo.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginInfo.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginProviderInfo.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginReceiverInfo.kt
 delete mode 100644 projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginServiceInfo.kt

diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/ShadowPluginLoader.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/ShadowPluginLoader.kt
index 3bc68bde4..eb9507e3d 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/ShadowPluginLoader.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/ShadowPluginLoader.kt
@@ -19,7 +19,6 @@
 package com.tencent.shadow.core.loader
 
 import android.content.Context
-import android.content.pm.PackageInfo
 import android.os.Handler
 import android.os.Looper
 import android.os.Parcel
@@ -69,11 +68,6 @@ abstract class ShadowPluginLoader(hostAppContext: Context) : DelegateProvider, D
      */
     abstract fun getComponentManager():ComponentManager
 
-    /**
-     * @GuardedBy("mLock")
-     */
-    private val mPluginPackageInfoSet: MutableSet<PackageInfo> = hashSetOf()
-
     private lateinit var mPluginServiceManager: PluginServiceManager
 
     private val mPluginContentProviderManager: PluginContentProviderManager = PluginContentProviderManager()
@@ -158,8 +152,6 @@ abstract class ShadowPluginLoader(hostAppContext: Context) : DelegateProvider, D
 
         return LoadPluginBloc.loadPlugin(
                 mExecutorService,
-                mPluginPackageInfoSet,
-                ::allPluginPackageInfo,
                 mComponentManager,
                 mLock,
                 mPluginPartsMap,
@@ -168,12 +160,6 @@ abstract class ShadowPluginLoader(hostAppContext: Context) : DelegateProvider, D
                 loadParameters)
     }
 
-    private fun allPluginPackageInfo(): Array<PackageInfo> {
-        mLock.withLock {
-            return mPluginPackageInfoSet.toTypedArray()
-        }
-    }
-
     override fun getHostActivityDelegate(aClass: Class<out HostActivityDelegator>): HostActivityDelegate {
         return if (HostNativeActivityDelegator::class.java.isAssignableFrom(aClass)) {
             ShadowNativeActivityDelegate(this)
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParsePluginApkBloc.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CheckPackageNameBloc.kt
similarity index 54%
rename from projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParsePluginApkBloc.kt
rename to projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CheckPackageNameBloc.kt
index e51baf19f..e19306596 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParsePluginApkBloc.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CheckPackageNameBloc.kt
@@ -19,33 +19,16 @@
 package com.tencent.shadow.core.loader.blocs
 
 import android.content.Context
-import android.content.pm.PackageInfo
-import android.os.Build
-import com.tencent.shadow.core.load_parameters.LoadParameters
 import com.tencent.shadow.core.loader.exceptions.ParsePluginApkException
-import com.tencent.shadow.core.loader.infos.*
+import com.tencent.shadow.core.runtime.PluginManifest
 
-/**
- * 解析插件apk逻辑
- *
- * @author cubershi
- */
-object ParsePluginApkBloc {
-    /**
-     * 解析插件apk
-     *
-     * @param pluginFile 插件apk文件
-     * @return 解析信息
-     * @throws ParsePluginApkException 解析失败时抛出
-     */
+object CheckPackageNameBloc {
     @Throws(ParsePluginApkException::class)
-    fun parse(
-        packageArchiveInfo: PackageInfo,
-        manifestInfo: ManifestInfo,
-        loadParameters: LoadParameters,
-        hostAppContext: Context
-    ): PluginInfo {
-        if (packageArchiveInfo.applicationInfo.packageName != hostAppContext.packageName) {
+    fun check(
+            pluginManifest: PluginManifest,
+            hostAppContext: Context
+    ) {
+        if (pluginManifest.applicationPackageName != hostAppContext.packageName) {
             /*
             要求插件和宿主包名一致有两方面原因：
             1.正常的构建过程中，aapt会将包名写入到arsc文件中。插件正常安装运行时，如果以
@@ -63,41 +46,7 @@ object ParsePluginApkBloc {
 
             我们也可以始终认为Shadow App是宿主的扩展代码，使用是宿主的一部分，那么采用宿主的包名就是理所应当的了。
              */
-            throw ParsePluginApkException("插件和宿主包名不一致。宿主:${hostAppContext.packageName} 插件:${packageArchiveInfo.applicationInfo.packageName}")
-        }
-
-        /*
-        partKey的作用是用来区分一个Component是来自于哪个插件apk的
-         */
-        val partKey = loadParameters.partKey
-
-        val pluginInfo = PluginInfo(
-                loadParameters.businessName,
-            partKey,
-            packageArchiveInfo.applicationInfo.packageName,
-            packageArchiveInfo.applicationInfo.className
-        )
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            pluginInfo.appComponentFactory = packageArchiveInfo.applicationInfo.appComponentFactory
-        }
-        packageArchiveInfo.activities?.forEach {
-            pluginInfo.putActivityInfo(PluginActivityInfo(it.name, it.themeResource, it))
-        }
-
-        val receiveMap = manifestInfo.receivers.map { it.name to it }.toMap()
-        packageArchiveInfo.receivers?.forEach {
-            pluginInfo.putReceiverInfo(
-                PluginReceiverInfo(
-                    it.name,
-                    it,
-                    receiveMap[it.name]?.actions()
-                )
-            )
-        }
-        packageArchiveInfo.services?.forEach { pluginInfo.putServiceInfo(PluginServiceInfo(it.name)) }
-        packageArchiveInfo.providers?.forEach {
-            pluginInfo.putPluginProviderInfo(PluginProviderInfo(it.name, it.authority, it))
+            throw ParsePluginApkException("插件和宿主包名不一致。宿主:${hostAppContext.packageName} 插件:${pluginManifest.applicationPackageName}")
         }
-        return pluginInfo
     }
 }
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateApplicationBloc.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateApplicationBloc.kt
index f985b558d..7b83f08ca 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateApplicationBloc.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateApplicationBloc.kt
@@ -21,10 +21,11 @@ package com.tencent.shadow.core.loader.blocs
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.content.res.Resources
+import com.tencent.shadow.core.load_parameters.LoadParameters
 import com.tencent.shadow.core.loader.classloaders.PluginClassLoader
 import com.tencent.shadow.core.loader.exceptions.CreateApplicationException
-import com.tencent.shadow.core.loader.infos.PluginInfo
 import com.tencent.shadow.core.loader.managers.ComponentManager
+import com.tencent.shadow.core.runtime.PluginManifest
 import com.tencent.shadow.core.runtime.ShadowAppComponentFactory
 import com.tencent.shadow.core.runtime.ShadowApplication
 
@@ -37,33 +38,32 @@ object CreateApplicationBloc {
     @Throws(CreateApplicationException::class)
     fun createShadowApplication(
             pluginClassLoader: PluginClassLoader,
-            pluginInfo: PluginInfo,
+            loadParameters: LoadParameters,
+            pluginManifest: PluginManifest,
             resources: Resources,
             hostAppContext: Context,
             componentManager: ComponentManager,
-            applicationInfo: ApplicationInfo,
+            pluginApplicationInfo: ApplicationInfo,
             appComponentFactory: ShadowAppComponentFactory
     ): ShadowApplication {
         try {
-            val appClassName = pluginInfo.applicationClassName
-                ?: ShadowApplication::class.java.name
+            val appClassName = pluginManifest.applicationClassName
+                    ?: ShadowApplication::class.java.name
             val shadowApplication =
-                appComponentFactory.instantiateApplication(pluginClassLoader, appClassName)
-            val partKey = pluginInfo.partKey
+                    appComponentFactory.instantiateApplication(pluginClassLoader, appClassName)
+            val partKey = loadParameters.partKey
             shadowApplication.setPluginResources(resources)
             shadowApplication.setPluginClassLoader(pluginClassLoader)
             shadowApplication.setPluginComponentLauncher(componentManager)
-            shadowApplication.setBroadcasts(pluginInfo.mReceivers.map { receiveInfo ->
-                receiveInfo.className!! to receiveInfo.actions
-            }.toMap())
+            shadowApplication.setBroadcasts(pluginManifest.receivers)
             shadowApplication.setAppComponentFactory(appComponentFactory)
-            shadowApplication.applicationInfo = applicationInfo
-            shadowApplication.setBusinessName(pluginInfo.businessName)
+            shadowApplication.applicationInfo = pluginApplicationInfo
+            shadowApplication.setBusinessName(loadParameters.businessName)
             shadowApplication.setPluginPartKey(partKey)
 
             //和ShadowActivityDelegate.initPluginActivity一样，attachBaseContext放到最后
             shadowApplication.setHostApplicationContextAsBase(hostAppContext)
-            shadowApplication.setTheme(applicationInfo.theme)
+            shadowApplication.setTheme(pluginManifest.applicationTheme)
             return shadowApplication
         } catch (e: Exception) {
             throw CreateApplicationException(e)
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreatePluginApplicationInfoBloc.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreatePluginApplicationInfoBloc.kt
new file mode 100644
index 000000000..ee736b056
--- /dev/null
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreatePluginApplicationInfoBloc.kt
@@ -0,0 +1,43 @@
+package com.tencent.shadow.core.loader.blocs
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.os.Build
+import com.tencent.shadow.core.common.InstalledApk
+import com.tencent.shadow.core.load_parameters.LoadParameters
+import com.tencent.shadow.core.runtime.PluginManifest
+import com.tencent.shadow.core.runtime.ShadowContext
+import java.io.File
+
+object CreatePluginApplicationInfoBloc {
+    fun create(installedApk: InstalledApk,
+               loadParameters: LoadParameters,
+               pluginManifest: PluginManifest,
+               hostAppContext: Context): ApplicationInfo {
+        val result = ApplicationInfo(hostAppContext.applicationInfo)
+        result.sourceDir = installedApk.apkFilePath
+        result.nativeLibraryDir = installedApk.libraryPath
+        result.dataDir = makeDataDir(loadParameters, hostAppContext).absolutePath
+
+        result.packageName = pluginManifest.applicationPackageName
+        result.className = pluginManifest.applicationClassName
+        result.theme = pluginManifest.applicationTheme
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            result.appComponentFactory = pluginManifest.appComponentFactory
+        }
+        return result
+    }
+
+    fun makeDataDir(loadParameters: LoadParameters, hostAppContext: Context): File {
+        val tempContext = ShadowContext(hostAppContext, 0).apply {
+            setBusinessName(loadParameters.businessName)
+        }
+        val dataDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            tempContext.dataDir
+        } else {
+            File(tempContext.filesDir, "dataDir")
+        }
+        dataDir.mkdirs()
+        return dataDir
+    }
+}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateResourceBloc.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateResourceBloc.kt
index 32e05abd1..0d28c8b9d 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateResourceBloc.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/CreateResourceBloc.kt
@@ -19,7 +19,7 @@
 package com.tencent.shadow.core.loader.blocs
 
 import android.content.Context
-import android.content.pm.PackageInfo
+import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.content.res.Resources
 import android.os.Handler
@@ -28,7 +28,7 @@ import android.webkit.WebView
 import java.util.concurrent.CountDownLatch
 
 object CreateResourceBloc {
-    fun create(packageArchiveInfo: PackageInfo, archiveFilePath: String, hostAppContext: Context): Resources {
+    fun create(archiveFilePath: String, hostAppContext: Context): Resources {
         //先用宿主context初始化一个WebView，以便WebView的逻辑去修改sharedLibraryFiles，将webview.apk添加进去
         val latch = CountDownLatch(1)
         Handler(Looper.getMainLooper()).post {
@@ -38,11 +38,14 @@ object CreateResourceBloc {
         latch.await()
 
         val packageManager = hostAppContext.packageManager
-        packageArchiveInfo.applicationInfo.publicSourceDir = archiveFilePath
-        packageArchiveInfo.applicationInfo.sourceDir = archiveFilePath
-        packageArchiveInfo.applicationInfo.sharedLibraryFiles = hostAppContext.applicationInfo.sharedLibraryFiles
+        val applicationInfo = ApplicationInfo()
+        applicationInfo.packageName = hostAppContext.applicationInfo.packageName
+        applicationInfo.uid = hostAppContext.applicationInfo.uid
+        applicationInfo.publicSourceDir = archiveFilePath
+        applicationInfo.sourceDir = archiveFilePath
+        applicationInfo.sharedLibraryFiles = hostAppContext.applicationInfo.sharedLibraryFiles
         try {
-            return packageManager.getResourcesForApplication(packageArchiveInfo.applicationInfo)
+            return packageManager.getResourcesForApplication(applicationInfo)
         } catch (e: PackageManager.NameNotFoundException) {
             throw RuntimeException(e)
         }
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/LoadPluginBloc.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/LoadPluginBloc.kt
index 183e0bf4a..d9b0b51a1 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/LoadPluginBloc.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/LoadPluginBloc.kt
@@ -19,9 +19,6 @@
 package com.tencent.shadow.core.loader.blocs
 
 import android.content.Context
-import android.content.pm.PackageInfo
-import android.content.pm.PackageManager
-import android.os.Build
 import com.tencent.shadow.core.common.InstalledApk
 import com.tencent.shadow.core.load_parameters.LoadParameters
 import com.tencent.shadow.core.loader.exceptions.LoadPluginException
@@ -31,7 +28,6 @@ import com.tencent.shadow.core.loader.managers.PluginPackageManagerImpl
 import com.tencent.shadow.core.runtime.PluginPartInfo
 import com.tencent.shadow.core.runtime.PluginPartInfoManager
 import com.tencent.shadow.core.runtime.ShadowAppComponentFactory
-import com.tencent.shadow.core.runtime.ShadowContext
 import java.io.File
 import java.util.concurrent.Callable
 import java.util.concurrent.ExecutorService
@@ -43,8 +39,6 @@ object LoadPluginBloc {
     @Throws(LoadPluginException::class)
     fun loadPlugin(
             executorService: ExecutorService,
-            pluginPackageInfoSet: MutableSet<PackageInfo>,
-            allPluginPackageInfo: () -> (Array<PackageInfo>),
             componentManager: ComponentManager,
             lock: ReentrantLock,
             pluginPartsMap: MutableMap<String, PluginParts>,
@@ -61,67 +55,45 @@ object LoadPluginBloc {
                 }
             })
 
-            val getPackageInfo = executorService.submit(Callable {
-                val archiveFilePath = installedApk.apkFilePath
-                val packageManager = hostAppContext.packageManager
-
-                val packageArchiveInfo = packageManager.getPackageArchiveInfo(
-                        archiveFilePath,
-                        PackageManager.GET_ACTIVITIES
-                                or PackageManager.GET_META_DATA
-                                or PackageManager.GET_SERVICES
-                                or PackageManager.GET_PROVIDERS
-                                or PackageManager.GET_RECEIVERS
-                                or PackageManager.GET_SIGNATURES
-                )
-                        ?: throw NullPointerException("getPackageArchiveInfo return null.archiveFilePath==$archiveFilePath")
-
-                val tempContext = ShadowContext(hostAppContext, 0).apply {
-                    setBusinessName(loadParameters.businessName)
-                }
-                val dataDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                    tempContext.dataDir
-                } else {
-                    File(tempContext.filesDir, "dataDir")
-                }
-                dataDir.mkdirs()
-
-                packageArchiveInfo.applicationInfo.nativeLibraryDir = installedApk.libraryPath
-                packageArchiveInfo.applicationInfo.dataDir = dataDir.absolutePath
-                packageArchiveInfo.applicationInfo.processName =
-                    hostAppContext.applicationInfo.processName
-                packageArchiveInfo.applicationInfo.uid = hostAppContext.applicationInfo.uid
-
-                lock.withLock { pluginPackageInfoSet.add(packageArchiveInfo) }
-                packageArchiveInfo
-            })
-
-            val buildManifestInfo = executorService.submit(Callable {
-                ParseManifestBloc.parse(hostAppContext, installedApk)
+            val buildPluginManifest = executorService.submit(Callable {
+                val pluginClassLoader = buildClassLoader.get()
+                val pluginManifest = pluginClassLoader.loadPluginManifest()
+                CheckPackageNameBloc.check(pluginManifest, hostAppContext)
+                pluginManifest
             })
 
-            val buildPluginInfo = executorService.submit(Callable {
-                val packageInfo = getPackageInfo.get()
-                val manifestInfo = buildManifestInfo.get()
-                ParsePluginApkBloc.parse(packageInfo, manifestInfo, loadParameters, hostAppContext)
+            val buildPluginApplicationInfo = executorService.submit(Callable {
+                val pluginManifest = buildPluginManifest.get()
+                val pluginApplicationInfo = CreatePluginApplicationInfoBloc.create(
+                        installedApk,
+                        loadParameters,
+                        pluginManifest,
+                        hostAppContext
+                )
+                pluginApplicationInfo
             })
 
             val buildPackageManager = executorService.submit(Callable {
-                val packageInfo = getPackageInfo.get()
+                val pluginApplicationInfo = buildPluginApplicationInfo.get()
                 val hostPackageManager = hostAppContext.packageManager
-                PluginPackageManagerImpl(hostPackageManager, packageInfo, allPluginPackageInfo)
+                PluginPackageManagerImpl(
+                        pluginApplicationInfo,
+                        installedApk.apkFilePath,
+                        componentManager,
+                        hostPackageManager,
+                )
             })
 
             val buildResources = executorService.submit(Callable {
-                val packageInfo = getPackageInfo.get()
-                CreateResourceBloc.create(packageInfo, installedApk.apkFilePath, hostAppContext)
+                CreateResourceBloc.create(installedApk.apkFilePath, hostAppContext)
             })
 
-            val buildAppComponentFactory = executorService.submit(Callable<ShadowAppComponentFactory> {
+            val buildAppComponentFactory = executorService.submit(Callable {
                 val pluginClassLoader = buildClassLoader.get()
-                val pluginInfo = buildPluginInfo.get()
-                if (pluginInfo.appComponentFactory != null) {
-                    val clazz = pluginClassLoader.loadClass(pluginInfo.appComponentFactory)
+                val pluginManifest = buildPluginManifest.get()
+                val appComponentFactory = pluginManifest.appComponentFactory
+                if (appComponentFactory != null) {
+                    val clazz = pluginClassLoader.loadClass(appComponentFactory)
                     ShadowAppComponentFactory::class.java.cast(clazz.newInstance())
                 } else ShadowAppComponentFactory()
             })
@@ -129,17 +101,18 @@ object LoadPluginBloc {
             val buildApplication = executorService.submit(Callable {
                 val pluginClassLoader = buildClassLoader.get()
                 val resources = buildResources.get()
-                val pluginInfo = buildPluginInfo.get()
-                val packageInfo = getPackageInfo.get()
                 val appComponentFactory = buildAppComponentFactory.get()
+                val pluginManifest = buildPluginManifest.get()
+                val pluginApplicationInfo = buildPluginApplicationInfo.get()
 
                 CreateApplicationBloc.createShadowApplication(
                         pluginClassLoader,
-                        pluginInfo,
+                        loadParameters,
+                        pluginManifest,
                         resources,
                         hostAppContext,
                         componentManager,
-                        packageInfo.applicationInfo,
+                        pluginApplicationInfo,
                         appComponentFactory
                 )
             })
@@ -151,17 +124,20 @@ object LoadPluginBloc {
                 val pluginPackageManager = buildPackageManager.get()
                 val pluginClassLoader = buildClassLoader.get()
                 val resources = buildResources.get()
-                val pluginInfo = buildPluginInfo.get()
                 val shadowApplication = buildApplication.get()
                 val appComponentFactory = buildAppComponentFactory.get()
+                val pluginManifest = buildPluginManifest.get()
                 lock.withLock {
-                    componentManager.addPluginApkInfo(pluginInfo)
-                    pluginPartsMap[pluginInfo.partKey] = PluginParts(
+                    componentManager.addPluginApkInfo(
+                            pluginManifest,
+                            loadParameters,
+                            installedApk.apkFilePath,
+                    )
+                    pluginPartsMap[loadParameters.partKey] = PluginParts(
                             appComponentFactory,
                             shadowApplication,
                             pluginClassLoader,
                             resources,
-                            pluginInfo.businessName,
                             pluginPackageManager
                     )
                     PluginPartInfoManager.addPluginInfo(pluginClassLoader, PluginPartInfo(shadowApplication, resources,
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParseManifestBloc.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParseManifestBloc.kt
deleted file mode 100644
index b296f23f8..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/blocs/ParseManifestBloc.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.tencent.shadow.core.loader.blocs
-
-import android.content.Context
-import android.content.IntentFilter
-import android.content.res.Resources
-import com.tencent.shadow.core.common.InstalledApk
-import com.tencent.shadow.core.loader.infos.ManifestInfo
-import com.tencent.shadow.core.loader.infos.ManifestInfo.Receiver
-import com.tencent.shadow.core.loader.infos.ManifestInfo.ReceiverIntentInfo
-import org.xmlpull.v1.XmlPullParser
-
-/**
- * 解析插件的AndroidManifest.xml文件
- * 由于系统开放接口不提供广播的action信息，此处采用手动解析的方式处理,减少插件化的适配工作
- * 后续对于AndroidManifest.xml的处理可在此基础上扩展
- *
- * @author xuedizi2009@163.com
- */
-object ParseManifestBloc {
-
-    private const val ANDROID_RESOURCES = "http://schemas.android.com/apk/res/android"
-    private const val TAG_RECEIVER = "receiver"
-    private const val TAG_INTENT_FILTER = "intent-filter"
-    private const val TAG_ACTION = "action"
-    private const val ATTR_NAME = "name"
-
-    @Throws(Exception::class)
-    fun parse(context: Context, installedApk: InstalledApk): ManifestInfo = ManifestInfo().apply {
-        val resources: Resources = newResource(context, installedApk)
-        val parser = resources.assets.openXmlResourceParser("AndroidManifest.xml")
-        val outerDepth = parser.depth
-        var type: Int
-        while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT
-            && (type != XmlPullParser.END_TAG || parser.depth > outerDepth)
-        ) {
-            if (type == XmlPullParser.START_TAG) {
-                parseBroadcastReceiver(parser, this)
-            }
-        }
-    }
-
-    /**
-     * 此处如果使用[LoadPluginBloc.loadPlugin]构建的resources,将包含WebView的resources,故需要重新创建
-     */
-    private fun newResource(context: Context, installedApk: InstalledApk): Resources {
-        val packageArchiveInfo =
-            context.packageManager.getPackageArchiveInfo(installedApk.apkFilePath, 0)!!
-        val packageManager = context.packageManager
-        packageArchiveInfo.applicationInfo?.publicSourceDir = installedApk.apkFilePath
-        packageArchiveInfo.applicationInfo?.sourceDir = installedApk.apkFilePath
-        return packageManager.getResourcesForApplication(packageArchiveInfo.applicationInfo)
-    }
-
-    private fun parseBroadcastReceiver(parser: XmlPullParser, manifestInfo: ManifestInfo) {
-        if (TAG_RECEIVER == parser.name) {
-            val receiver = Receiver(parser.getAttributeValue(ANDROID_RESOURCES, ATTR_NAME))
-            val outerDepth = parser.depth
-            var type: Int
-            while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                        || parser.depth > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue
-                }
-                if (TAG_INTENT_FILTER == parser.name) {
-                    val receiverInfo = ReceiverIntentInfo()
-                    parserIntent(parser, receiverInfo)
-                    receiver.intents.add(receiverInfo)
-                }
-            }
-            manifestInfo.receivers.add(receiver)
-        }
-    }
-
-    private fun parserIntent(parser: XmlPullParser, intentFilter: IntentFilter) {
-        val outerDepth = parser.depth
-        var type: Int
-        while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT
-            && (type != XmlPullParser.END_TAG || parser.depth > outerDepth)
-        ) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue
-            }
-            if (TAG_ACTION == parser.name) {
-                val value = parser.getAttributeValue(ANDROID_RESOURCES, ATTR_NAME)
-                intentFilter.addAction(value)
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowActivityDelegate.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowActivityDelegate.kt
index 64fe64492..d954f38df 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowActivityDelegate.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowActivityDelegate.kt
@@ -31,7 +31,6 @@ import android.view.LayoutInflater
 import android.view.WindowManager
 import com.tencent.shadow.coding.java_build_config.BuildConfig
 import com.tencent.shadow.core.common.LoggerFactory
-import com.tencent.shadow.core.loader.infos.PluginActivityInfo
 import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_ACTIVITY_INFO_KEY
 import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_BUSINESS_NAME_KEY
 import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_CALLING_ACTIVITY_KEY
@@ -39,10 +38,7 @@ import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_CLA
 import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_EXTRAS_BUNDLE_KEY
 import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_LOADER_BUNDLE_KEY
 import com.tencent.shadow.core.loader.managers.ComponentManager.Companion.CM_PART_KEY
-import com.tencent.shadow.core.runtime.MixResources
-import com.tencent.shadow.core.runtime.PluginActivity
-import com.tencent.shadow.core.runtime.ShadowActivity
-import com.tencent.shadow.core.runtime.ShadowActivityLifecycleCallbacks
+import com.tencent.shadow.core.runtime.*
 import com.tencent.shadow.core.runtime.container.HostActivityDelegate
 import com.tencent.shadow.core.runtime.container.HostActivityDelegator
 
@@ -84,7 +80,7 @@ open class ShadowActivityDelegate(private val mDI: DI) : GeneratedShadowActivity
     private lateinit var mCurrentConfiguration: Configuration
     private var mPluginHandleConfigurationChange: Int = 0
     private var mCallingActivity: ComponentName? = null
-    protected lateinit var mPluginActivityInfo: PluginActivityInfo
+    protected lateinit var mPluginActivityInfo: PluginManifest.ActivityInfo
 
     override fun onCreate(savedInstanceState: Bundle?) {
         val pluginInitBundle = savedInstanceState ?: mHostActivityDelegator.intent.extras!!
@@ -102,12 +98,12 @@ open class ShadowActivityDelegate(private val mDI: DI) : GeneratedShadowActivity
         mBundleForPluginLoader = bundleForPluginLoader
         bundleForPluginLoader.classLoader = this.javaClass.classLoader
         val pluginActivityClassName = bundleForPluginLoader.getString(CM_CLASS_NAME_KEY)!!
-        val pluginActivityInfo: PluginActivityInfo = bundleForPluginLoader.getParcelable(CM_ACTIVITY_INFO_KEY)!!
+        val pluginActivityInfo: PluginManifest.ActivityInfo = bundleForPluginLoader.getParcelable(CM_ACTIVITY_INFO_KEY)!!
         mPluginActivityInfo = pluginActivityInfo
 
         mCurrentConfiguration = Configuration(resources.configuration)
         mPluginHandleConfigurationChange =
-                (pluginActivityInfo.activityInfo!!.configChanges
+                (pluginActivityInfo.configChanges
                         or ActivityInfo.CONFIG_SCREEN_SIZE//系统本身就会单独对待这个属性，不声明也不会重启Activity。
                         or ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE//系统本身就会单独对待这个属性，不声明也不会重启Activity。
                         or 0x20000000 //见ActivityInfo.CONFIG_WINDOW_CONFIGURATION 系统处理属性
@@ -135,7 +131,7 @@ open class ShadowActivityDelegate(private val mDI: DI) : GeneratedShadowActivity
             mHostActivityDelegator.window.callback = pluginActivity
 
             //设置插件AndroidManifest.xml 中注册的WindowSoftInputMode
-            mHostActivityDelegator.window.setSoftInputMode(pluginActivityInfo.activityInfo.softInputMode)
+            mHostActivityDelegator.window.setSoftInputMode(pluginActivityInfo.softInputMode)
 
             //Activity.onCreate调用之前应该先收到onWindowAttributesChanged。
             if (mCallOnWindowAttributesChanged) {
@@ -158,7 +154,7 @@ open class ShadowActivityDelegate(private val mDI: DI) : GeneratedShadowActivity
         }
     }
 
-    private fun initPluginActivity(pluginActivity: PluginActivity, pluginActivityInfo: PluginActivityInfo) {
+    private fun initPluginActivity(pluginActivity: PluginActivity, pluginActivityInfo: PluginManifest.ActivityInfo) {
         pluginActivity.setHostActivityDelegator(mHostActivityDelegator)
         pluginActivity.setPluginResources(mPluginResources)
         pluginActivity.setPluginClassLoader(mPluginClassLoader)
@@ -176,7 +172,13 @@ open class ShadowActivityDelegate(private val mDI: DI) : GeneratedShadowActivity
         //有可能会执行业务Activity覆盖的逻辑。
         //所以，这个调用要放在最后。
         pluginActivity.setHostContextAsBase(mHostActivityDelegator.hostActivity as Context)
-        pluginActivity.setTheme(pluginActivityInfo.themeResource)
+
+        val activityTheme = if (pluginActivityInfo.theme != 0) {
+            pluginActivityInfo.theme
+        } else {
+            pluginActivity.applicationInfo.theme
+        }
+        pluginActivity.setTheme(activityTheme)
     }
 
     override fun getLoaderVersion() = BuildConfig.VERSION_NAME
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowNativeActivityDelegate.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowNativeActivityDelegate.kt
index 1c75aaf1e..649de01f6 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowNativeActivityDelegate.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowNativeActivityDelegate.kt
@@ -5,6 +5,7 @@ import android.content.pm.ActivityInfo
 import android.content.pm.PackageManager
 import android.view.InputQueue
 import android.view.SurfaceHolder
+import com.tencent.shadow.core.runtime.PackageManagerInvokeRedirect
 import com.tencent.shadow.core.runtime.ShadowNativeActivity
 import com.tencent.shadow.core.runtime.container.HostNativeActivityDelegate
 
@@ -45,9 +46,11 @@ class ShadowNativeActivityDelegate(mDI: DI) : ShadowActivityDelegate(mDI),
 
     //预期只有NativeActivity会调用这个方法
     override fun getPackageManager(): PackageManager {
+        val pluginPackageManager =
+                PackageManagerInvokeRedirect.getPluginPackageManager(mPluginActivity.classLoader)
         return object : PackageManagerWrapper(mHostActivityDelegator.superGetPackageManager()) {
             override fun getActivityInfo(component: ComponentName, flags: Int): ActivityInfo {
-                return mPluginActivityInfo.activityInfo!!
+                return pluginPackageManager.getActivityInfo(component, flags)
             }
         }
     }
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/ManifestInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/ManifestInfo.kt
deleted file mode 100644
index f2415d85b..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/ManifestInfo.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.tencent.shadow.core.loader.infos
-
-import android.content.IntentFilter
-
-/**
- * 插件AndroidManifest.xml信息存储类
- *
- * @author xuedizi2009@163.com
- */
-class ManifestInfo {
-    val receivers = mutableListOf<Receiver>()
-
-    class Receiver(val name: String) {
-        var intents = mutableListOf<ReceiverIntentInfo>()
-
-        fun actions(): MutableList<String> {
-            val actions = mutableListOf<String>()
-            this.intents.forEach { intentInfo ->
-                intentInfo.actionsIterator().forEach { action ->
-                    actions.add(action)
-                }
-            }
-            return actions
-        }
-    }
-
-    class ReceiverIntentInfo : IntentFilter()
-}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginActivityInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginActivityInfo.kt
deleted file mode 100644
index cbbad51ab..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginActivityInfo.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Tencent is pleased to support the open source community by making Tencent Shadow available.
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.  All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.tencent.shadow.core.loader.infos
-
-import android.content.pm.ActivityInfo
-import android.os.Parcel
-import android.os.Parcelable
-
-class PluginActivityInfo(className: String?, val themeResource: Int, val activityInfo: ActivityInfo?) : Parcelable, PluginComponentInfo(className) {
-    constructor(parcel: Parcel) : this(
-            parcel.readString(),
-            parcel.readInt(),
-            parcel.readParcelable(ActivityInfo::class.java.classLoader)) {
-    }
-
-    override fun writeToParcel(parcel: Parcel, flags: Int) {
-        parcel.writeString(className)
-        parcel.writeInt(themeResource)
-        parcel.writeParcelable(activityInfo, flags)
-    }
-
-    override fun describeContents(): Int {
-        return 0
-    }
-
-    companion object CREATOR : Parcelable.Creator<PluginActivityInfo> {
-        override fun createFromParcel(parcel: Parcel): PluginActivityInfo {
-            return PluginActivityInfo(parcel)
-        }
-
-        override fun newArray(size: Int): Array<PluginActivityInfo?> {
-            return arrayOfNulls(size)
-        }
-    }
-}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginComponentInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginComponentInfo.kt
deleted file mode 100644
index 6de1f7a7e..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginComponentInfo.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Tencent is pleased to support the open source community by making Tencent Shadow available.
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.  All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.tencent.shadow.core.loader.infos
-
-import android.os.Parcelable
-
-abstract class PluginComponentInfo(val className: String?) : Parcelable
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginInfo.kt
deleted file mode 100644
index 40ea0f986..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginInfo.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Tencent is pleased to support the open source community by making Tencent Shadow available.
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.  All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.tencent.shadow.core.loader.infos
-
-class PluginInfo(
-        val businessName: String?,
-        val partKey: String,
-        val packageName: String,
-        val applicationClassName: String?
-) {
-    private val _mActivities: MutableSet<PluginActivityInfo> = HashSet()
-    private val _mServices: MutableSet<PluginServiceInfo> = HashSet()
-    private val _mProviders: MutableSet<PluginProviderInfo> = HashSet()
-    private val _mReceivers: MutableSet<PluginReceiverInfo> = HashSet()
-    internal val mActivities: Set<PluginActivityInfo>
-        get() = _mActivities
-    internal val mServices: Set<PluginServiceInfo>
-        get() = _mServices
-    internal val mProviders: Set<PluginProviderInfo>
-        get() = _mProviders
-    internal val mReceivers: Set<PluginReceiverInfo>
-        get() = _mReceivers
-
-    internal var appComponentFactory: String? = null
-
-    fun putActivityInfo(pluginActivityInfo: PluginActivityInfo) {
-        _mActivities.add(pluginActivityInfo)
-    }
-
-    fun putServiceInfo(pluginServiceInfo: PluginServiceInfo) {
-        _mServices.add(pluginServiceInfo)
-    }
-
-    fun putPluginProviderInfo(pluginProviderInfo: PluginProviderInfo) {
-        _mProviders.add(pluginProviderInfo)
-    }
-
-    fun putReceiverInfo(pluginReceiverInfo: PluginReceiverInfo) {
-        _mReceivers.add(pluginReceiverInfo)
-    }
-}
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginParts.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginParts.kt
index 56342ce83..e6c1a148c 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginParts.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginParts.kt
@@ -29,6 +29,5 @@ class PluginParts(
         val application: ShadowApplication,
         val classLoader: PluginClassLoader,
         val resources: Resources,
-        val businessName: String?,
         val pluginPackageManager: PluginPackageManager
 )
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginProviderInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginProviderInfo.kt
deleted file mode 100644
index 5f273ce12..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginProviderInfo.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Tencent is pleased to support the open source community by making Tencent Shadow available.
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.  All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.tencent.shadow.core.loader.infos
-
-import android.content.pm.ProviderInfo
-import android.os.Parcel
-import android.os.Parcelable
-
-class PluginProviderInfo(className: String?, val authority: String?, val providerInfo: ProviderInfo?) : Parcelable, PluginComponentInfo(className) {
-    constructor(parcel: Parcel) : this(
-            parcel.readString(),
-            parcel.readString(),
-            parcel.readParcelable(ProviderInfo::class.java.classLoader)) {
-    }
-
-    override fun writeToParcel(parcel: Parcel, flags: Int) {
-        parcel.writeString(className)
-        parcel.writeString(authority)
-        parcel.writeParcelable(providerInfo, flags)
-    }
-
-    override fun describeContents(): Int {
-        return 0
-    }
-
-    companion object CREATOR : Parcelable.Creator<PluginProviderInfo> {
-        override fun createFromParcel(parcel: Parcel): PluginProviderInfo {
-            return PluginProviderInfo(parcel)
-        }
-
-        override fun newArray(size: Int): Array<PluginProviderInfo?> {
-            return arrayOfNulls(size)
-        }
-    }
-}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginReceiverInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginReceiverInfo.kt
deleted file mode 100644
index 33d347aa6..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginReceiverInfo.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.tencent.shadow.core.loader.infos
-
-import android.content.pm.ActivityInfo
-import android.os.Parcel
-import android.os.Parcelable
-import android.os.Parcelable.Creator
-
-/**
- * 插件广播数据
- * @author xuedizi2009@163.com
- */
-class PluginReceiverInfo(
-    className: String?,
-    private val activityInfo: ActivityInfo?,
-    val actions: List<String>?
-) : Parcelable, PluginComponentInfo(className) {
-    constructor(parcel: Parcel) : this(
-        parcel.readString(),
-        parcel.readParcelable(ActivityInfo::class.java.classLoader),
-        parcel.createStringArrayList()
-    )
-
-    override fun writeToParcel(parcel: Parcel, flags: Int) {
-        parcel.writeString(className)
-        parcel.writeParcelable(activityInfo, flags)
-        parcel.writeStringList(actions)
-    }
-
-    override fun describeContents(): Int {
-        return 0
-    }
-
-    companion object CREATOR : Creator<PluginReceiverInfo> {
-        override fun createFromParcel(parcel: Parcel): PluginReceiverInfo {
-            return PluginReceiverInfo(parcel)
-        }
-
-        override fun newArray(size: Int): Array<PluginReceiverInfo?> {
-            return arrayOfNulls(size)
-        }
-    }
-}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginServiceInfo.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginServiceInfo.kt
deleted file mode 100644
index 1a947c8fe..000000000
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/PluginServiceInfo.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Tencent is pleased to support the open source community by making Tencent Shadow available.
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.  All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.tencent.shadow.core.loader.infos
-
-import android.os.Parcel
-import android.os.Parcelable
-
-/**
- * Created by tracyluo on 2018/6/7.
- */
-class PluginServiceInfo(className: String?) : Parcelable, PluginComponentInfo(className) {
-    constructor(parcel: Parcel) : this(
-            parcel.readString())
-
-    override fun writeToParcel(dest: Parcel, flags: Int) {
-        dest.writeString(className)
-    }
-
-    override fun describeContents(): Int {
-        return 0
-    }
-
-    companion object CREATOR : Parcelable.Creator<PluginServiceInfo> {
-        override fun createFromParcel(parcel: Parcel): PluginServiceInfo {
-            return PluginServiceInfo(parcel)
-        }
-
-        override fun newArray(size: Int): Array<PluginServiceInfo?> {
-            return arrayOfNulls(size)
-        }
-    }
-}
\ No newline at end of file
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt
index 0c6ab02c5..18aa02e60 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt
@@ -24,9 +24,9 @@ import android.content.ServiceConnection
 import android.os.Bundle
 import android.util.Pair
 import com.tencent.shadow.coding.java_build_config.BuildConfig
+import com.tencent.shadow.core.load_parameters.LoadParameters
 import com.tencent.shadow.core.loader.infos.ContainerProviderInfo
-import com.tencent.shadow.core.loader.infos.PluginComponentInfo
-import com.tencent.shadow.core.loader.infos.PluginInfo
+import com.tencent.shadow.core.runtime.PluginManifest
 import com.tencent.shadow.core.runtime.ShadowContext
 import com.tencent.shadow.core.runtime.ShadowContext.PluginComponentLauncher
 import com.tencent.shadow.core.runtime.container.DelegateProvider.LOADER_VERSION_KEY
@@ -146,59 +146,67 @@ abstract class ComponentManager : PluginComponentLauncher {
 
     /**
      * key:插件ComponentName
-     * value:PluginInfo
+     * value:LoadParameters
      */
-    private val pluginInfoMap: MutableMap<ComponentName, PluginInfo> = hashMapOf()
+    private val loadParametersMap: MutableMap<ComponentName, LoadParameters> = hashMapOf()
 
     /**
      * key:插件ComponentName
-     * value:PluginComponentInfo
+     * value:PluginManifest.ActivityInfo
      */
-    private val pluginComponentInfoMap: MutableMap<ComponentName, PluginComponentInfo> = hashMapOf()
+    private val pluginActivityInfoMap: MutableMap<ComponentName, PluginManifest.ActivityInfo> = hashMapOf()
 
+    /**
+     * 保存所有已加载插件对PluginManifest和apk文件路径对应关系
+     * 用于在同一个Loader加载对多个插件之间相互查找组件
+     */
+    private val allLoadedPlugin: MutableList<kotlin.Pair<PluginManifest, String>> = mutableListOf()
 
-    fun addPluginApkInfo(pluginInfo: PluginInfo) {
-        fun common(pluginComponentInfo: PluginComponentInfo,componentName:ComponentName) {
-            packageNameMap[pluginComponentInfo.className!!] = pluginInfo.packageName
-            val previousValue = pluginInfoMap.put(componentName, pluginInfo)
+    fun addPluginApkInfo(pluginManifest: PluginManifest, loadParameters: LoadParameters, archiveFilePath: String) {
+        fun common(componentInfo: PluginManifest.ComponentInfo, componentName: ComponentName) {
+            packageNameMap[componentInfo.className] = componentName.packageName
+            val previousValue = loadParametersMap.put(componentName, loadParameters)
             if (previousValue != null) {
                 throw IllegalStateException("重复添加Component：$componentName")
             }
-            pluginComponentInfoMap[componentName] = pluginComponentInfo
         }
 
-        pluginInfo.mActivities.forEach {
-            val componentName = ComponentName(pluginInfo.packageName, it.className!!)
-            common(it,componentName)
+        val applicationPackageName = pluginManifest.applicationPackageName
+        pluginManifest.activities?.forEach {
+            val componentName = ComponentName(applicationPackageName, it.className)
+            common(it, componentName)
             componentMap[componentName] = onBindContainerActivity(componentName)
+            pluginActivityInfoMap[componentName] = it
         }
 
-        pluginInfo.mServices.forEach {
-            val componentName = ComponentName(pluginInfo.packageName, it.className!!)
+        pluginManifest.services?.forEach {
+            val componentName = ComponentName(applicationPackageName, it.className)
             common(it, componentName)
         }
 
-        pluginInfo.mProviders.forEach {
-            val componentName = ComponentName(pluginInfo.packageName, it.className!!)
+        pluginManifest.providers?.forEach {
+            val componentName = ComponentName(applicationPackageName, it.className)
             mPluginContentProviderManager!!.addContentProviderInfo(
-                pluginInfo.partKey,
-                it,
-                onBindContainerContentProvider(componentName)
+                    loadParameters.partKey,
+                    it,
+                    onBindContainerContentProvider(componentName)
             )
         }
 
-        pluginInfo.mReceivers.forEach {
-            val componentName = ComponentName(pluginInfo.packageName, it.className!!)
+        pluginManifest.receivers?.forEach {
+            val componentName = ComponentName(applicationPackageName, it.className)
             common(it, componentName)
         }
+
+        allLoadedPlugin.add(pluginManifest to archiveFilePath)
     }
 
     fun getComponentBusinessName(componentName: ComponentName): String? {
-        return pluginInfoMap[componentName]?.businessName
+        return loadParametersMap[componentName]?.businessName
     }
 
     fun getComponentPartKey(componentName: ComponentName) : String? {
-        return pluginInfoMap[componentName]?.partKey
+        return loadParametersMap[componentName]?.partKey
     }
 
     private var mPluginServiceManager : PluginServiceManager? = null
@@ -222,8 +230,8 @@ abstract class ComponentManager : PluginComponentLauncher {
      */
     private fun Intent.toActivityContainerIntent(): Intent {
         val bundleForPluginLoader = Bundle()
-        val pluginComponentInfo = pluginComponentInfoMap[component]!!
-        bundleForPluginLoader.putParcelable(CM_ACTIVITY_INFO_KEY, pluginComponentInfo)
+        val pluginActivityInfo = pluginActivityInfoMap[component]!!
+        bundleForPluginLoader.putParcelable(CM_ACTIVITY_INFO_KEY, pluginActivityInfo)
         return toContainerIntent(bundleForPluginLoader)
     }
 
@@ -233,17 +241,24 @@ abstract class ComponentManager : PluginComponentLauncher {
      * 调用前必须先调用isPluginComponent判断Intent确实一个插件内的组件
      */
     private fun Intent.toContainerIntent(bundleForPluginLoader: Bundle): Intent {
-        val component = this.component!!
+        val component = this.component
+                ?: throw IllegalArgumentException("Activity Intent必须指定ComponentName")
         val className = component.className
-        val packageName = packageNameMap[className]!!
+
+        val packageName = packageNameMap[className]
+                ?: throw IllegalArgumentException("已加载的插件中找不到${className}对应的packageName")
         this.component = ComponentName(packageName, className)
-        val containerComponent = componentMap[component]!!
-        val businessName = pluginInfoMap[component]!!.businessName
-        val partKey = pluginInfoMap[component]!!.partKey
+
+        val loadParameters = loadParametersMap[component]
+                ?: throw IllegalArgumentException("已加载的插件中找不到${component}对应的LoadParameters")
+        val businessName = loadParameters.businessName
+        val partKey = loadParameters.partKey
 
         val pluginExtras: Bundle? = extras
         replaceExtras(null as Bundle?)
 
+        val containerComponent = componentMap[component]
+                ?: throw IllegalArgumentException("已加载的插件中找不到${component}对应的ContainerActivity")
         val containerIntent = Intent(this)
         containerIntent.component = containerComponent
 
@@ -258,4 +273,44 @@ abstract class ComponentManager : PluginComponentLauncher {
         containerIntent.putExtra(PROCESS_ID_KEY, DelegateProviderHolder.sCustomPid)
         return containerIntent
     }
+
+    fun getArchiveFilePathForActivity(className: String) =
+            getArchiveFilePath(className, PluginManifest::getActivities)
+
+    fun getArchiveFilePathForService(className: String) =
+            getArchiveFilePath(className, PluginManifest::getServices)
+
+    fun getArchiveFilePathForProvider(action: String?): kotlin.Pair<String?, String?> {
+        for ((pluginManifest, archiveFilePath) in allLoadedPlugin) {
+            val providers = pluginManifest.providers
+            if (providers != null) {
+                for (provider in providers) {
+                    if (action?.equals(provider.authorities) == true) {
+                        return provider.className to archiveFilePath
+                    }
+                }
+            }
+        }
+        return null to null
+    }
+
+    fun getAllArchiveFilePaths() = allLoadedPlugin.map { it.second }.toList()
+
+    private fun getArchiveFilePath(
+            className: String,
+            getComponents: (PluginManifest) -> Array<out PluginManifest.ComponentInfo>?
+    ): String? {
+        for ((pluginManifest, archiveFilePath) in allLoadedPlugin) {
+            val components = getComponents(pluginManifest)
+            if (components != null) {
+                for (component in components) {
+                    if (component.className == className) {
+                        return archiveFilePath
+                    }
+                }
+            }
+        }
+        return null
+    }
+
 }
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt
index 477c9c856..d61a26f78 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt
@@ -20,11 +20,12 @@ package com.tencent.shadow.core.loader.managers
 
 import android.content.ContentProvider
 import android.content.Context
+import android.content.pm.ProviderInfo
 import android.net.Uri
 import android.os.Bundle
 import com.tencent.shadow.core.loader.infos.ContainerProviderInfo
 import com.tencent.shadow.core.loader.infos.PluginParts
-import com.tencent.shadow.core.loader.infos.PluginProviderInfo
+import com.tencent.shadow.core.runtime.PluginManifest
 import com.tencent.shadow.core.runtime.UriConverter
 import java.util.*
 import kotlin.collections.HashSet
@@ -44,7 +45,7 @@ class PluginContentProviderManager() : UriConverter.UriParseDelegate {
     private val providerAuthorityMap = HashMap<String, String>()
 
 
-    private val pluginProviderInfoMap = HashMap<String, HashSet<PluginProviderInfo>?>()
+    private val pluginProviderInfoMap = HashMap<String, HashSet<PluginManifest.ProviderInfo>?>()
 
 
     override fun parse(uriString: String): Uri {
@@ -66,13 +67,13 @@ class PluginContentProviderManager() : UriConverter.UriParseDelegate {
         return pluginUri
     }
 
-    fun addContentProviderInfo(partKey: String, pluginProviderInfo: PluginProviderInfo, containerProviderInfo: ContainerProviderInfo) {
-        if (providerMap.containsKey(pluginProviderInfo.authority)) {
+    fun addContentProviderInfo(partKey: String, pluginProviderInfo: PluginManifest.ProviderInfo, containerProviderInfo: ContainerProviderInfo) {
+        if (providerMap.containsKey(pluginProviderInfo.authorities)) {
             throw RuntimeException("重复添加 ContentProvider")
         }
 
-        providerAuthorityMap[pluginProviderInfo.authority!!] = containerProviderInfo.authority
-        var pluginProviderInfos: HashSet<PluginProviderInfo>? = null
+        providerAuthorityMap[pluginProviderInfo.authorities] = containerProviderInfo.authority
+        var pluginProviderInfos: HashSet<PluginManifest.ProviderInfo>? = null
         if (pluginProviderInfoMap.containsKey(partKey)) {
             pluginProviderInfos = pluginProviderInfoMap[partKey]
         } else {
@@ -82,15 +83,23 @@ class PluginContentProviderManager() : UriConverter.UriParseDelegate {
         pluginProviderInfoMap.put(partKey, pluginProviderInfos)
     }
 
-    fun createContentProviderAndCallOnCreate(mContext: Context, partKey: String, pluginParts: PluginParts?) {
+    fun createContentProviderAndCallOnCreate(context: Context, partKey: String, pluginParts: PluginParts?) {
         pluginProviderInfoMap[partKey]?.forEach {
             try {
                 val contentProvider = pluginParts!!.appComponentFactory
                         .instantiateProvider(pluginParts.classLoader, it.className)
-                contentProvider?.attachInfo(mContext, it.providerInfo)
-                providerMap[it.authority!!] = contentProvider
+
+                //convert PluginManifest.ProviderInfo to android.content.pm.ProviderInfo
+                val providerInfo = ProviderInfo()
+                providerInfo.packageName = context.packageName
+                providerInfo.name = it.className
+                providerInfo.authority = it.authorities
+                providerInfo.grantUriPermissions = true //插件没有权限管理机制
+
+                contentProvider?.attachInfo(context, providerInfo)
+                providerMap[it.authorities] = contentProvider
             } catch (e: Exception) {
-                throw RuntimeException("partKey==$partKey className==${it.className} providerInfo==${it.providerInfo}", e)
+                throw RuntimeException("partKey==$partKey className==${it.className} authorities==${it.authorities}", e)
             }
         }
 
diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginPackageManagerImpl.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginPackageManagerImpl.kt
index 03e17b134..3f86c81d3 100644
--- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginPackageManagerImpl.kt
+++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginPackageManagerImpl.kt
@@ -18,124 +18,156 @@
 
 package com.tencent.shadow.core.loader.managers
 
+import android.annotation.SuppressLint
 import android.content.ComponentName
 import android.content.Intent
 import android.content.pm.*
 import com.tencent.shadow.core.runtime.PluginPackageManager
 
-internal class PluginPackageManagerImpl(private val hostPackageManager: PackageManager,
-                                        private val packageInfo: PackageInfo,
-                                        private val allPluginPackageInfo: () -> (Array<PackageInfo>))
-    : PluginPackageManager {
+@SuppressLint("WrongConstant")
+internal class PluginPackageManagerImpl(private val pluginApplicationInfoFromPluginManifest: ApplicationInfo,
+                                        private val pluginArchiveFilePath: String,
+                                        private val componentManager: ComponentManager,
+                                        private val hostPackageManager: PackageManager
+) : PluginPackageManager {
     override fun getApplicationInfo(packageName: String, flags: Int): ApplicationInfo =
-            if (packageInfo.applicationInfo.packageName == packageName) {
-                packageInfo.applicationInfo
+            if (packageName.isPlugin()) {
+                getPluginApplicationInfo(flags)
             } else {
                 hostPackageManager.getApplicationInfo(packageName, flags)
             }
 
     override fun getPackageInfo(packageName: String, flags: Int): PackageInfo? =
-            if (packageInfo.applicationInfo.packageName == packageName) {
+            if (packageName.isPlugin()) {
+                val packageInfo = hostPackageManager.getPackageArchiveInfo(pluginArchiveFilePath, flags)
+                if (packageInfo != null) {
+                    packageInfo.applicationInfo = getPluginApplicationInfo(flags)
+                }
                 packageInfo
             } else {
                 hostPackageManager.getPackageInfo(packageName, flags)
             }
 
-    override fun getActivityInfo(component: ComponentName, flags: Int): ActivityInfo {
-        if (component.packageName == packageInfo.applicationInfo.packageName) {
-            val pluginActivityInfo = allPluginPackageInfo()
-                    .mapNotNull { it.activities }
-                    .flatMap { it.asIterable() }.find {
-                        it.name == component.className
-                    }
-            if (pluginActivityInfo != null) {
-                return pluginActivityInfo
+    override fun getActivityInfo(component: ComponentName, flags: Int): ActivityInfo? =
+            getComponentInfo(
+                    component,
+                    flags,
+                    ComponentManager::getArchiveFilePathForActivity,
+                    PackageManager.GET_ACTIVITIES,
+                    { it?.activities },
+                    PackageManager::getActivityInfo
+            )
+
+    override fun getServiceInfo(component: ComponentName, flags: Int): ServiceInfo? =
+            getComponentInfo(
+                    component,
+                    flags,
+                    ComponentManager::getArchiveFilePathForService,
+                    PackageManager.GET_SERVICES,
+                    { it?.services },
+                    PackageManager::getServiceInfo
+            )
+
+    override fun resolveActivity(intent: Intent, flags: Int): ResolveInfo? {
+        val component = intent.component
+        if (component != null) {
+            val activityInfo = getActivityInfo(component, flags)
+            if (activityInfo != null) {
+                val resolveInfo = ResolveInfo()
+                resolveInfo.activityInfo = activityInfo
+                return resolveInfo
             }
         }
-        return hostPackageManager.getActivityInfo(component, flags)
+        return hostPackageManager.resolveActivity(intent, flags)
     }
 
-    override fun getServiceInfo(component: ComponentName, flags: Int): ServiceInfo {
-      if (component.packageName == packageInfo.applicationInfo.packageName) {
-        val pluginServiceInfo = allPluginPackageInfo()
-          .mapNotNull { it.services }
-          .flatMap { it.asIterable() }.find {
-            it.name == component.className
-          }
-        if (pluginServiceInfo != null) {
-          return pluginServiceInfo
+    override fun resolveService(intent: Intent, flags: Int): ResolveInfo? {
+        val component = intent.component
+        if (component != null) {
+            val serviceInfo = getServiceInfo(component, flags)
+            if (serviceInfo != null) {
+                val resolveInfo = ResolveInfo()
+                resolveInfo.serviceInfo = serviceInfo
+                return resolveInfo
+            }
         }
-      }
-      return hostPackageManager.getServiceInfo(component, flags)
+        return hostPackageManager.resolveService(intent, flags)
     }
 
-    override fun resolveContentProvider(name: String, flags: Int): ProviderInfo? {
-        val pluginProviderInfo = allPluginPackageInfo()
-                .providers().find {
-                    it.authority == name
+    private fun <T : ComponentInfo> getComponentInfo(
+            component: ComponentName,
+            flags: Int,
+            getArchiveFilePath: ComponentManager.(String) -> String?,
+            componentGetFlag: Int,
+            getFromPackageInfo: (PackageInfo?) -> Array<T>?,
+            getFromHost: PackageManager.(component: ComponentName, flags: Int) -> T?
+    ): T? {
+
+        if (component.packageName.isPlugin()) {
+            val archiveFilePath = componentManager.getArchiveFilePath(component.className)
+            if (archiveFilePath != null) {
+                val packageInfo = hostPackageManager.getPackageArchiveInfo(
+                        archiveFilePath, componentGetFlag or flags
+                )
+                val componentInfo = getFromPackageInfo(packageInfo)?.find {
+                    it.name == component.className
                 }
-        if (pluginProviderInfo != null) {
-            return pluginProviderInfo
+                if (componentInfo != null) {
+                    return componentInfo
+                }
+            }
         }
+        return hostPackageManager.getFromHost(component, flags)
+    }
 
+    override fun resolveContentProvider(name: String, flags: Int): ProviderInfo? {
+        val (className, archiveFilePath) = componentManager.getArchiveFilePathForProvider(name)
+        if (archiveFilePath != null) {
+            val packageInfo = hostPackageManager.getPackageArchiveInfo(
+                    archiveFilePath, PackageManager.GET_PROVIDERS or flags
+            )
+            val componentInfo = packageInfo?.providers?.find {
+                it.name == className
+            }
+            if (componentInfo != null) {
+                return componentInfo
+            }
+        }
         return hostPackageManager.resolveContentProvider(name, flags)
     }
 
     override fun queryContentProviders(processName: String?, uid: Int, flags: Int) =
             if (processName == null) {
-                val allNormalProviders = hostPackageManager.queryContentProviders(null, 0, flags)
-                val allPluginProviders = allPluginPackageInfo().providers()
+                val allNormalProviders =
+                        hostPackageManager.queryContentProviders(null, 0, flags)
+                val allPluginProviders = allPluginProviders(flags)
                 listOf(allNormalProviders, allPluginProviders).flatten()
+            } else if (processName == pluginApplicationInfoFromPluginManifest.processName &&
+                    uid == pluginApplicationInfoFromPluginManifest.uid) {
+                allPluginProviders(flags)
             } else {
-                allPluginPackageInfo().filter {
-                    it.applicationInfo.processName == processName
-                            && it.applicationInfo.uid == uid
-                }.providers()
+                hostPackageManager.queryContentProviders(processName, uid, flags)
             }
 
-    override fun resolveActivity(intent: Intent, flags: Int): ResolveInfo {
-        val hostResolveInfo = hostPackageManager.resolveActivity(intent, flags)
-        return if (hostResolveInfo?.activityInfo == null) {
-            ResolveInfo().apply {
-                activityInfo = allPluginPackageInfo()
-                        .flatMap { it.activities.asIterable() }
-                        .find {
-                            it.name == intent.component?.className
-                        }
+    private fun allPluginProviders(flags: Int): List<ProviderInfo> =
+            componentManager.getAllArchiveFilePaths().flatMap {
+                val packageInfo = hostPackageManager.getPackageArchiveInfo(it,
+                        PackageManager.GET_PROVIDERS or flags)
+                packageInfo?.providers?.asList().orEmpty()
             }
-        } else {
-            hostResolveInfo
-        }
-    }
 
-    override fun resolveService(intent: Intent, flags: Int): ResolveInfo {
-        val hostResolveInfo = hostPackageManager.resolveService(intent, flags)
-        return if (hostResolveInfo?.serviceInfo == null) {
-            ResolveInfo().apply {
-                serviceInfo = allPluginPackageInfo()
-                        .flatMap { it.services.asIterable() }
-                        .find {
-                            it.name == intent.component?.className
-                        }
-            }
-        } else {
-            hostResolveInfo
-        }
-    }
+    private fun String.isPlugin() = pluginApplicationInfoFromPluginManifest.packageName == this
 
-    private fun Array<PackageInfo>.providers(): List<ProviderInfo> {
-        return this.asIterable().providers()
-    }
+    private fun getPluginApplicationInfo(flags: Int): ApplicationInfo {
+        val copy = ApplicationInfo(pluginApplicationInfoFromPluginManifest)
 
-    private fun Iterable<PackageInfo>.providers(): List<ProviderInfo> {
-        return this.flatMap {
-            if (it.providers != null) {
-                it.providers.asIterable()
-            } else {
-                emptyList()
-            }
+        val needMetaData = flags and PackageManager.GET_META_DATA != 0
+        if (needMetaData) {
+            val packageInfo = hostPackageManager.getPackageArchiveInfo(pluginArchiveFilePath, PackageManager.GET_META_DATA)!!
+            val metaData = packageInfo.applicationInfo.metaData
+            copy.metaData = metaData
         }
-    }
-
 
+        return copy
+    }
 }
\ No newline at end of file
diff --git a/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PackageManagerInvokeRedirect.java b/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PackageManagerInvokeRedirect.java
index dd28855c3..02beae194 100644
--- a/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PackageManagerInvokeRedirect.java
+++ b/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PackageManagerInvokeRedirect.java
@@ -40,7 +40,7 @@
  */
 public class PackageManagerInvokeRedirect {
 
-    private static PluginPackageManager getPluginPackageManager(ClassLoader classLoaderOfInvokeCode) {
+    public static PluginPackageManager getPluginPackageManager(ClassLoader classLoaderOfInvokeCode) {
         return PluginPartInfoManager.getPluginInfo(classLoaderOfInvokeCode).packageManager;
     }
 
diff --git a/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowApplication.java b/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowApplication.java
index 7e7b7ce7b..a46710252 100644
--- a/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowApplication.java
+++ b/projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowApplication.java
@@ -29,6 +29,8 @@
 import android.content.res.Configuration;
 import android.os.Build;
 
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -148,8 +150,14 @@ public void setHostApplicationContextAsBase(Context hostAppContext) {
                 = new ShadowActivityLifecycleCallbacks.Holder(mHostApplication);
     }
 
-    public void setBroadcasts(Map<String, List<String>> broadcast){
-        mBroadcasts = broadcast;
+    public void setBroadcasts(PluginManifest.ReceiverInfo[] receiverInfos) {
+        Map<String, List<String>> classNameToActions = new HashMap<>();
+        if (receiverInfos != null) {
+            for (PluginManifest.ReceiverInfo receiverInfo : receiverInfos) {
+                classNameToActions.put(receiverInfo.className, Arrays.asList(receiverInfo.actions));
+            }
+        }
+        mBroadcasts = classNameToActions;
     }
 
     public void attachBaseContext(Context base) {
