美文网首页框架安卓Android知识
插件化知识梳理(1) - Small 框架之如何引入应用插件

插件化知识梳理(1) - Small 框架之如何引入应用插件

作者: 泽毛 | 来源:发表于2017-06-03 10:10 被阅读869次

    相关阅读

    插件化知识梳理(1) - Small 框架之如何引入应用插件
    插件化知识梳理(2) - Small 框架之如何引入公共库插件
    插件化知识梳理(3) - Small 框架之宿主分身
    插件化知识梳理(4) - Small 框架之如何实现插件更新
    插件化知识梳理(5) - Small 框架之如何不将插件打包到宿主中
    插件化知识梳理(6) - Small 源码分析之 Hook 原理
    插件化知识梳理(7) - 类的动态加载入门
    插件化知识梳理(8) - 类的动态加载源码分析
    插件化知识梳理(9) - 资源的动态加载示例及源码分析
    插件化知识梳理(10) - Service 插件化实现及原理


    一、前言

    上个星期,公司里有一个小的讲座,对插件化进行了简单的介绍,因此决定开始研究一下这方面的知识。

    在网上查了一些相关的资料,发现了Small这个开源的插件化框架,因此打算从它入手,通过它的内部实现,学习一下插件化的相关原理。这篇文章是个开篇,先从一个简单的例子开始,把环境给搭建好。先给大家分享一些这几天查阅的资料,如果大家有比较好的文章也可以留言或者私信我:

    Android博客周刊专题之#插件化开发#

    Small Github 官网
    Small Issues
    Small 快速入门

    Android Small 源码分析 (一) 启动流程
    Android Small 源码分析 (二) 插件加载过程

    Android Small 插件化框架源码分析

    Android Small 插件化框架 -- 启动插件 Activity 源码解析(上)
    Android Small 插件化框架 -- 启动插件 Activity 源码解析(下)
    Android Small 插件化框架 -- Android 应用类加载机制
    Android Small 插件化框架 -- 类加载实现解析

    二、基本示例

    2.1 简要介绍

    对于Small来说,一个最简单的框架分为三个部分:

    • 宿主
    • 插件
    • bundle.json,用于宿主和插件之间的路由。

    本文所用的是一个最简单的例子,因此在代码上基本不会有什么问题,主要是环境上的区别,遇到编译不过的问题可以多多百度,下面是我所采用的环境:

    • Android Studio 版本:Android Studio 3.0
    • Gradle 版本:gradle-3.5-all.zip
    • compileSdkVersion24
    • buildToolsVersion24.0.2

    完整的例子可以查看 https://github.com/imZeJun/SmallDemo

    2.2 具体实现

    整个具体的实现分为五步:

    • 新建工程/宿主模块
    • 修改项目根目录下的build.gradle文件,引入Small插件
    • 新建插件模块
    • 完善宿主模块
    • 编译,安装

    2.2.1 新建工程/宿主模块

    这里比较关键的一点,是需要在新建工程/宿主模块的时候,将包名修正为com.demo.small,这是为了和以后的lib/app模块形成统一:

    2.2.2 修改项目根目录下的 build.gradle 文件

    对于项目的build.gradle,修改包含以下三个部分:

    • 必选,在dependencies节点中引入远程依赖。
    • 必选,通过apply plugin应用插件。
    • 可选,配置Small代码库版本。
    buildscript {
    
        repositories {
            maven { url 'https://maven.google.com' }
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.2.3'
            //1.引入Small依赖,必选。
            classpath 'net.wequick.tools.build:gradle-small:1.2.0-alpha3'
        }
    }
    
    allprojects {
        repositories {
            jcenter()
            maven { url 'https://maven.google.com' }
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
    //2.应用插件,必选。
    apply plugin: 'net.wequick.small'
    
    //3.配置Small的代码库版本,需要放在第2步的下面,否则会报错,可选。
    small {
        aarVersion = '1.2.0-alpha3'
    }
    

    2.2.3 新建插件模块

    这里用到的插件模块很简单,就是位于另一个模块中的Activity,选择File -> New -> New Module


    插件模块中最最关键的一点,就是插件模块的包名,它的包名分为两个部分
    • 第一部分和宿主模块相同
    • 第二部分要根据插件的类型来决定:
    • 如果是Phone & Tablet Module:那么要以app.xxx结尾
    • 如果是Android Library,那么要以lib.xxx结尾

    这里,我们先演示第一种:


    在插件模块中,我们声明一个新的PlugActivity,它的布局为:
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        tools:context="com.demo.small.app.main.PlugActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textColor="@android:color/black"
            android:text="PlugActivity started success"/>
    
    </FrameLayout>
    

    2.2.4 完善宿主模块

    (a) 配置路由协议

    接下来要在宿主模块中进行路由配置,我们在宿主模块上单击右键,新建一个assets文件夹,之后在assets文件夹中,新建一个路由文件,bundle.json文件,注意assets文件夹从Project视图上所处的位置如下图所示,千万不要放错地方了:


    bundle.json中,我们声明插件模块:
    {
      "version": "1.0.0",
      "bundles": [
        {
          "uri": "main",
          "pkg": "com.demo.small.app.main"
        }
      ]
    }
    

    ** (b) 在宿主模块的自定义 Application 中进行预加载**

    public class SmallHostApp extends Application {
    
        public SmallHostApp() {
            //Small初始化。
            Small.preSetUp(this);
        }
    }
    

    ** (c) 将自定义的 Application 配置到宿主模块的 AndroidManifest.xml 中**

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.demo.small">
    
        <application
            android:name=".app.SmallHostApp"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".LaunchActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    ** (d) 在启动 Activity 的 onCreate() 方法中加载插件,点击按钮后跳转到插件的Activity**

    public class LaunchActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_launch);
            setUp();
        }
    
        private void setUp() {
            Small.setUp(this, new net.wequick.small.Small.OnCompleteListener() {
    
                @Override
                public void onComplete() {
                    Log.d("LaunchActivity", "onComplete");
                }
            });
        }
    
        public void startPlugActivity(View view) {
            Small.openUri("main", LaunchActivity.this);
        }
    }
    

    2.2.5 编译&安装

    最后一步,就是进行编译和安装,编译时:

    • 准备基础库 & 打包所有组件
    ./gradlew buildLib -q && ./gradlew buildBundle -q
    
    • 安装:
     ./gradlew assembleDebug && adb install -r app/build/outputs/apk/app-debug.apk 
    
    • 清除基础库 & 清除所有组件:
    ./gradlew cleanLib -q && ./gradlew cleanBundle -q
    

    2.3 最终效果


    更多文章,欢迎访问我的 Android 知识梳理系列:

    相关文章

      网友评论

      • d8df68146d7f:你好,按照你的方法吃创建了app.main 编译后报错
        Error:Execution failed for task ':app.main:preBuild'.
        > Could not get unknown property 'libraries' for task ':app.main:processDebugManifest' of type com.android.build.gradle.tasks.MergeManifests.

        请问如何解决
        泽毛:@lwhan 感觉可能是 gradle 版本的问题,你的和我的一样吗
        d8df68146d7f:@泽毛 已经问了,而且看了之前也有人问。。不过都没有得到好的解决方法。。。:unamused:
        泽毛:@lwhan 之前没有遇到过这个问题,可以到 https://github.com/wequick/Small/issues 问一下,会有专门的人解答
      • 小新GG:楼主 请教个问题, 我这边宿主调用插件一直报TextView错 ,但是单独运行插件却可以, 将布局文件TextView改为ImageView又可以运行, 请问这是为什么呀 .main.PluginActivity}: android.view.InflateException: Binary XML file line #10: Binary XML file line #10: Error inflating class TextView
        34e9e4ff1b14:把AS换成2.3看看,我AS用3.0就报错,2.3就没有问题了
        泽毛:@小新GG 这个是别的错误引起的加载 xml 异常,你要看下最后面的报错是什么。
      • 晨北北:真好,
        泽毛:@创意公元 多谢支持:relaxed:
      • different_loyal:这种适合app的插件开发,不适合SDK的插件开发吧?
        泽毛:@你可以叫我鑫仔 嗯,这个框架确实是为 App 设计的。
      • o动感超人o:我想知道你的代码中的startPlugActivity这个方法在哪里调用的
        泽毛:@o动感超人o 聪明,就是这样的。
        o动感超人o:@泽毛 哦,那你是不是在xml的TextView里没有写android:onClick这个属性,我看代码里也没写
        泽毛:点了 startPlugActivity 那段文字之后调用的
      • 草蜢的逆袭:插件之间可以互相调用里面的api吗
        草蜢的逆袭: @泽毛 好的,谢谢
        泽毛:@syusikoku 应用插件可以调用共同库插件里面的 API,但是一个应用插件不可以调用另一个应用插件的 API,关于共同库插件和应用插件的区别可以看第二篇文章。

      本文标题:插件化知识梳理(1) - Small 框架之如何引入应用插件

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