Using ComposeUI to realize Android plug-in

What is Compose

Jetpack Compose is the Android UI implementation method officially recommended by Google. It avoids the shortcomings of Android traditional View in terms of drawing, writing, and performance. For specific usage methods, please refer to the official documentation.

Compose and plug-in

Presumably everyone has been in contact with or understands plug-in development, and friends who have not been in contact with it need to make up lessons. In the past plug-in development process, there must be an Activity (in the host) in the manifest file, and hooks and reflection methods are required to pass the life cycle of the host’s Activity to the plug-in. The configuration problem is serious, which has caused many obstacles to plug-in development. Using ComposeUI, all views are composable-widgets (this is very similar to cross-platform Flutter). ComposeUI also brings optimization space to plug-in, loading in the host A certain Composable component of the plugin is more flexible and has higher performance. Note: The Android View method can also realize the functions of this article, but the View drawing efficiency is low and the performance is poor. The principle of using Compose to realize plug-in is the same as that of traditional plug-in, mainly omitting the process of creating Activity and passing the life cycle with black technology.

project creation

  1. Create a project, nothing new, no pictures here
  2. Create a plug-in project: Add a module in the project, I named it plugin here, add a variable configuration in the gradle.properties file in the project root directory runAlone=trueto configure whether the plugin can run independently
  3. Modify the gradle configuration of the plugin module as follows:
plugins {
    
    
    id 'org.jetbrains.kotlin.android'
}
def aloneRun = runAlone.toBoolean()
//根据runalone配置,动态添加gradle的plugin
if (aloneRun) {
    
    
    plugins.apply('com.android.application')
} else {
    
    
    plugins.apply('com.android.library')
}
...
  defaultConfig {
    
    
        if (aloneRun) {
    
    
            //plugin模块作为application时的applicationId
            applicationId "tech.wcw.compose.plugin"
        }
  }
...
        //plugin模块作为application时添加源文件目录和清单文件,方便开发和测试(compose方式可以通过@Preview预览,按需添加)
        if (aloneRun) {
    
    
            sourceSets {
    
    
                main.java.srcDirs += 'src/alone/java'
                main.manifest.srcFile 'src/alone/AndroidManifest.xml'
            }
        }

plugin implementation

  • Method 1: There is a pit here! ! ! The declared Composable component is compiled with (Composer, Int) parameters. The latter parameter is closely related to recombination. If the parameters cannot be passed correctly when calling, strange bugs may occur. Directly declare the Composable component, and declare the Composable component through the @Composable annotation.
@Composable
 fun pluginView(param: String) {
    
    
     Log.i(tag, "pluginView v1 重组")
     Box(
         modifier = Modifier
             .background(Color.Red)
             .fillMaxWidth()
             .height(40.dp)
     ) {
    
    
         Text(text = "收到宿主传参 $param")
     }
 }

  • Method 2: Indirect call by lambda expression, that is, to declare the Composable component as a function expression, which is expressed as FunctionN (0~23) in java after compilation, which is related to whether the Composable component passes parameters, and can be added in the compiled file View specific types in
val pluginView: (@Composable () -> Unit) = {
    
    
    Log.i(tag, "pluginView v2 重组")
    Box(
        modifier = Modifier
            .background(Color.Blue)
            .fillMaxWidth()
            .height(40.dp)
    )
}

host implementation

  1. Package the plugin into assets (for demo demonstration, the actual development should be downloaded from the server)
  2. Get dex, create classLoader (demo simple processing, not merged dex)
fun loadPlugin(context: Context) {
    
    
    val inputStream = context.assets.open("plugin.apk")
    val filesDir = context.externalCacheDir
    val apkFile = File(filesDir?.absolutePath, "plugin.apk")
    apkFile.writeBytes(inputStream.readBytes())

    val dexFile = File(filesDir, "dex")
    if (!dexFile.exists()) dexFile.mkdirs()
    println("dexPath: $dexFile")
    pluginClassLoader = DexClassLoader(
        apkFile.absolutePath,
        dexFile.absolutePath,
        null,
        this.javaClass.classLoader
    )
}

3. Load the plug-in, obtain the Class through ClassLoader, obtain the corresponding method through reflection, and call it by passing parameters. Note: Method 1: pass parameters to Composer and changed by yourself, the latter will affect the reorganization, so be careful ! The second method does not need to pass the parameters by yourself, and it is handled by compose black technology.

private fun applyPluginV1() {
    
    
    val plugin = PluginManager.loadClass("tech.wcw.compose.plugin.PluginV1")
    plugin?.let {
    
    
        val method: Method =
            plugin.getDeclaredMethod(
                "pluginView",
                String::class.java,
                Composer::class.java,
                Int::class.java
            )
        method.isAccessible = true
        pluginV1Obj = plugin.newInstance()
        pluginV1Method = method
        applyV1Success = true
    }
}

private fun applyPluginV2() {
    
    
    val plugin = PluginManager.loadClass("tech.wcw.compose.plugin.PluginV2")
    plugin?.let {
    
    
        val method: Method = plugin.getDeclaredMethod("getPluginView")
        method.isAccessible = true
        val obj = plugin.newInstance()
        pluginV2Compose = method.invoke(obj) as (@Composable () -> Unit)
        applyV2Success = true
    }
}

at last

If you want to become an architect or want to break through the 20-30K salary range, then don't be limited to coding and business, but you must be able to select models, expand, and improve programming thinking. In addition, a good career plan is also very important, and the habit of learning is very important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here I would like to share with you a set of "Advanced Notes on the Eight Major Modules of Android" written by the senior architect of Ali, to help you organize the messy, scattered and fragmented knowledge systematically, so that you can systematically and efficiently Master the various knowledge points of Android development.
img
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

Welcome everyone to support with one click and three links. If you need the information in the article, you can directly scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓

PS: There is also a ChatGPT robot in the group, which can answer your work or technical questions
picture

Guess you like

Origin blog.csdn.net/weixin_43440181/article/details/132049522