美文网首页
Android插件化学习总结

Android插件化学习总结

作者: Goach | 来源:发表于2018-04-10 16:39 被阅读54次

插件化概念

个人总结为:它是由宿主和插件应用结合而成,两者遵守一些标准规范的情况下,插件无需安装,即可按需加载使用!

插件化优点

  • 宿主和插件分开编译
  • 并发进行开发
  • 动态更新插件
  • 按需下载模块
  • 方法数和变量数 65536问题

插件化步骤

  • 插件化分为宿主应用和插件应用
  • 新建Project - 也就是宿主应用
  • 新建一个Module,具有生命周期接口,宿主跳插件应用需要遵守一些标准规范
  • 新建Table Module - 也就是插件应用,同时在BaseActivity里面实现生命周期接口
  • Module通过attach方法注入上下文context,因为插件apk未安装,所以不能直接使用插件的上下文
  • 插件里面重写setContextView(),getWindowManger,getClassLoader这些需要使用上下文的方法,然后使用注入的that进行替换super调用
  • 在宿主app里面创建ProxyActivity,通过插桩的方式进行注册插件的Activity。ProxyActivity里面获取跳转传入的className,同时重写getClassLoader和getResource的方法,替换为PluginManager创建的ClassLoader和Resource
  • 创建PluginManager,单例的形式创建,实现loadPath方法,去加载apk(DexClassLoader)。因为 未安装就不能通过getClassLoader的方式Class.forName这样的方式了
  • 加载未安装apk(DexClassLoader)
  • 插件二级Activity的地方回传到宿主APP里面,BaseActivity里面startActivity

主要代码有:
1、初始化插件的ClassLoader,插件的主Activity,插件的Resources

object PluginManager {
    private lateinit var dexClassLoader:DexClassLoader
    private lateinit var resource:Resources
    private var entryActivityName:String = ""
    fun loadPath(context:Context,path: String){
        //获取插件的ClassLoader
        val dexOutFile = context.getDir("dex",Context.MODE_PRIVATE)
        dexClassLoader = DexClassLoader(path,dexOutFile.absolutePath,null,context.classLoader)
        //插件的第一个Activity
        val packageManager = context.packageManager
        val packageInfo = packageManager.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES)
        entryActivityName =  packageInfo.activities[0].name
        //实例化Resource
        val assetManager = AssetManager::class.java.newInstance()
        AssetManager::class.java.getDeclaredMethod("addAssetPath",String::class.java).invoke(assetManager,path)
        resource = Resources(assetManager,context.resources.displayMetrics,context.resources.configuration)
    }
    fun getClassLoader() = dexClassLoader
    fun getResource() = resource
    fun getEntryActivityName() = entryActivityName
}

2、插桩的形式创建ProxyActivity

class ProxyActivity : Activity() {
    private var className: String? = null
    private var aliPayInterface: IAliPay? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        className = intent.getStringExtra("className")
        try {
            val activityClass = classLoader.loadClass(className)
            val constructor = activityClass.getConstructor(*arrayOf())
            val instance = constructor.newInstance(*arrayOf())
            aliPayInterface = instance as IAliPay
            aliPayInterface!!.attach(this)
            val bundle = Bundle()
            aliPayInterface!!.onCreate(bundle)

        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        } catch (e: NoSuchMethodException) {
            e.printStackTrace()
        } catch (e: SecurityException) {
            e.printStackTrace()
        } catch (e: InstantiationException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            e.printStackTrace()
        }

    }

    override fun onStart() {
        super.onStart()
        aliPayInterface!!.onStart()
    }

    override fun onResume() {
        super.onResume()
        aliPayInterface!!.onResume()
    }

    override fun onPause() {
        super.onPause()
        aliPayInterface!!.onPause()
    }

    override fun onStop() {
        super.onStop()
        aliPayInterface!!.onStop()
    }

    override fun onDestroy() {
        super.onDestroy()
        aliPayInterface!!.onDestroy()
    }

    override fun getClassLoader(): ClassLoader {
        return PluginManager.getClassLoader()
    }

    override fun getResources(): Resources {
        return PluginManager.getResource()
    }

    override fun startActivity(intent: Intent) {
        val classNameFromTaoPiaoPiao = intent.getStringExtra("className")
        val newIntent = Intent(this, ProxyActivity::class.java)
        newIntent.putExtra("className", classNameFromTaoPiaoPiao)
        startActivity(newIntent)
    }
}

通过插件的classLoader和传入的className获取到约定规范的AliPay接口,然后调用插件里面主Activity的生命周期,同时重写ProxyActivity的跳转,从而实现插件的二级页面的跳转。

详细Demo查看Github-GoachAlipay

相关文章

网友评论

      本文标题:Android插件化学习总结

      本文链接:https://www.haomeiwen.com/subject/uzknhftx.html