Android 组件化的应用 模块通信问题解决
16lz
2021-01-23
组件之间AndroidManifest合并问题
由于 Android 项目在 Eclipse 和 AndroidStudio开发时 AndroidManifest.xml 文件的位置是不一样的,我们需要在build.gradle 中指定下 AndroidManifest.xml 的位置,AndroidStudio 才能读取到 AndroidManifest.xml,这样解决办法也就有了,我们可以为组件开发模式下的业务组件再创建一个 AndroidManifest.xml,然后根据isModule指定AndroidManifest.xml的文件路径,让业务组件在集成模式和组件模式下使用不同的AndroidManifest.xml,这样表单冲突的问题就可以规避了。 ———————————————— 2,如果组件模式下, 则需要重新设置 AndroidManifest.xml 文件,里面配置新的Application路径。比如Login组件单独运行 AndroidManifest 清单文件 if (!isModule.toBoolean()) { implementation project(':b-main') implementation project(':b-login') implementation project(':b-setting')}
解决的问题 1.Application 需要看下applicatin的初始化 有自己的application。
代理的application的作用
LoginApplicationDelegate
/** * login组件全局应用配置 * Created by chenran3 on 2017/12/6. */@EFModuleAnnotation(moduleName = "b-login",delegateName = "com.cryallen.applogin.LoginApplicationDelegate")public class LoginApplicationDelegate implements IApplicationDelegate { private static final String TAG = "LoginApplicationDelegate"; @Override public void onCreate() { EFLog.d(TAG, "*------------------onCreate()---------------->"); } @Override public void enterBackground() { EFLog.d(TAG, "*------------------enterBackground()---------------->"); } @Override public void enterForeground() { EFLog.d(TAG, "*------------------enterForeground()---------------->"); } @Override public void receiveRemoteNotification(Map, String> message) { EFLog.d(TAG, "receiveRemoteNotification msg = " + message); } @Override public void onTerminate() { EFLog.d(TAG, "*------------------onTerminate()---------------->"); } @Override public void onConfigurationChanged(Configuration configuration) { EFLog.d(TAG, "*------------------onConfigurationChanged()---------------->"); } @Override public void onLowMemory() { EFLog.d(TAG, "*------------------onLowMemory()---------------->"); } @Override public void onTrimMemory(int var1) { EFLog.d(TAG, "*------------------onTrimMemory()---------------->"); }}
2.清单文件多个,解决app和单独module的配置 1)组件模式和集成模式的转换 Android Studio中的Module主要有两种属性,分别为: 1、application属性,可以独立运行的Android程序,也就是我们的APP; apply plugin: ‘com.android.application’ 1 2、library属性,不可以独立运行,一般是Android程序依赖的库文件; apply plugin: ‘com.android.library’ ———————————————— sourceSets { main { if (isModule.toBoolean()) { manifest.srcFile 'src/main/module/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' //集成开发模式下排除debug文件夹中的所有Java文件 java { exclude 'debug/**' } } }}
3.切换app和切换组件的变量???? 目录中生成一个文件 gradle.properties,我们将使用这个文件的一个重要属性:在Android项目中的任何一个build.gradle文件中都可以把gradle.properties中的常量读取出来;那么我们在上面提到解决办法就有了实际行动的方法,首先我们在gradle.properties中定义一个常量值 isModule(是否是组件开发模式,true为是,false为否): # 每次更改“isModule”的值后,需要点击 "Sync Project" 按钮 isModule=false ——————————————— 实现原理: asset目录下的json配置 /** * * 加载模块信息 */public void loadModule() { Context context = getApplicationContext(); appDelegateList = new ArrayList(); delegateNameList = new ArrayList(); try { AssetManager assetManager = context.getResources().getAssets(); String[] fileList = assetManager.list(""); int fileLength = fileList.length; for(int i = 0; i < fileLength; ++i) { String fileName = fileList[i]; if(fileName.startsWith(MODULE_PREFIX)) { //解析json配置文件 ModuleInfo moduleInfo = parse(assetManager.open(fileName)); if(moduleInfo == null){ continue; } moduleInfoList.add(moduleInfo); delegateNameList.add(moduleInfo.getPackageName()); EFLog.d(TAG, "load Module: " + moduleInfo.getModuleName()); } } appDelegateList.addAll(ModuleClassUtils.getObjectsWithClassName(context, IApplicationDelegate.class, delegateNameList)); } catch (Exception e) { e.printStackTrace(); }}
转存失败重新上传取消 登入的解决办法: 业务组件自己的 Application 可以在组件开发模式下初始化一些数据,例如在组件开发模式下,A组件没有登录页面也没法登录,因此就无法获取到 Token,这样请求网络就无法成功,因此我们需要在A组件这个 APP 启动后就应该已经登录了,这时候组件自己的 Application 类就有了用武之地,我们在组件的 Application的 onCreate 方法中模拟一个登陆接口,在登陆成功后将数据保存到本地,这样就可以处理A组件中的数据业务了;另外我们也可以在组件Application中初始化一些第三方库。 ———————————————— 4)library依赖问题 在介绍这一节的时候,先说一个问题,在组件化工程模型图中,多媒体组件和Common组件都依赖了日志组件,而A业务组件有同时依赖了多媒体组件和Common组件,这时候就会有人问,你这样搞岂不是日志组件要被重复依赖了,而且Common组件也被每一个业务组件依赖了,这样不出问题吗? 其实大家完全没有必要担心这个问题,如果真有重复依赖的问题,在你编译打包的时候就会报错,如果你还是不相信的话可以反编译下最后打包出来的APP,看看里面的代码你就知道了。组件只是我们在代码开发阶段中为了方便叫的一个术语,在组件被打包进APP的时候是没有这个概念的,这些组件最后都会被打包成arr包,然后被app壳工程所依赖,在构建APP的过程中Gradle会自动将重复的arr包排除,APP中也就不会存在相同的代码了; 但是虽然组件是不会重复了,但是我们还是要考虑另一个情况,我们在build.gradle中compile的第三方库,例如AndroidSupport库经常会被一些开源的控件所依赖,而我们自己一定也会compile AndroidSupport库 ,这就会造成第三方包和我们自己的包存在重复加载,解决办法就是找出那个多出来的库,并将多出来的库给排除掉,而且Gradle也是支持这样做的,分别有两种方式:根据组件名排除或者根据包名排除,下面以排除support-v4库为例: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") { exclude module: 'support-v4'//根据组件名排除 exclude group: 'android.support.v4'//根据包名排除 } } library重复依赖的问题算是都解决了,但是我们在开发项目的时候会依赖很多开源库,而这些库每个组件都需要用到,要是每个组件都去依赖一遍也是很麻烦的,尤其是给这些库升级的时候,为了方便我们统一管理第三方库,我们将给给整个工程提供统一的依赖第三方库的入口,前面介绍的Common库的作用之一就是统一依赖开源库,因为其他业务组件都依赖了Common库,所以这些业务组件也就间接依赖了Common所依赖的开源库。 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) //Android Support compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion" compile "com.android.support:design:$rootProject.supportLibraryVersion" compile "com.android.support:percent:$rootProject.supportLibraryVersion" //网络请求相关 compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion" compile "com.squareup.retrofit2:retrofit-mock:$rootProject.retrofitVersion" compile "com.github.franmontiel:PersistentCookieJar:$rootProject.cookieVersion" //稳定的 compile "com.github.bumptech.glide:glide:$rootProject.glideVersion" compile "com.orhanobut:logger:$rootProject.loggerVersion" compile "org.greenrobot:eventbus:$rootProject.eventbusVersion" compile "com.google.code.gson:gson:$rootProject.gsonVersion" compile "com.github.chrisbanes:PhotoView:$rootProject.photoViewVersion" compile "com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion" compile "com.github.GrenderG:Toasty:$rootProject.toastyVersion" //router compile "com.github.mzule.activityrouter:activityrouter:$rootProject.routerVersion" } ———————————————— APT: 这一步我们需要先了解 APT这个概念,APT(Annotation Processing Tool)是一种处理注解的工具, 它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。在这里我们将在每一个业务组件的 build.gradle 都引入ActivityRouter 的 Annotation处理器,我们将会在声明组件和Url的时候使用,annotationProcessor是Android官方提供的Annotation处理器插件,代码如下: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) annotationProcessor "com.github.mzule.activityrouter:compiler:$rootProject.annotationProcessor" } ———————————————— 4、组件化项目的工程类型 在组件化工程模型中主要有:app壳工程、业务组件和功能组件3种类型,而业务组件中的Main组件和功能组件中的Common组件比较特殊,下面将分别介绍。 1)app壳工程 app壳工程是从名称来解释就是一个空壳工程,没有任何的业务代码,也不能有Activity,但它又必须被单独划分成一个组件,而不能融合到其他组件中,是因为它有如下几点重要功能: 1、app壳工程中声明了我们Android应用的 Application,这个 Application 必须继承自 Common组件中的 BaseApplication(如果你无需实现自己的Application可以直接在表单声明BaseApplication),因为只有这样,在打包应用后才能让BaseApplication中的Context生效,当然你还可以在这个 Application中初始化我们工程中使用到的库文件,还可以在这里解决Android引用方法数不能超过 65535 的限制,对崩溃事件的捕获和发送也可以在这里声明。 2、app壳工程的 AndroidManifest.xml 是我Android应用的根表单,应用的名称、图标以及是否支持备份等等属性都是在这份表单中配置的,其他组件中的表单最终在集成开发模式下都被合并到这份 AndroidManifest.xml 中。 3、app壳工程的 build.gradle 是比较特殊的,app壳不管是在集成开发模式还是组件开发模式,它的属性始终都是:com.android.application,因为最终其他的组件都要被app壳工程所依赖,被打包进app壳工程中,这一点从组件化工程模型图中就能体现出来,所以app壳工程是不需要单独调试单独开发的。另外Android应用的打包签名,以及buildTypes和defaultConfig都需要在这里配置,而它的dependencies则需要根据isModule的值分别依赖不同的组件,在组件开发模式下app壳工程只需要依赖Common组件,或者为了防止报错也可以根据实际情况依赖其他功能组件,而在集成模式下app壳工程必须依赖所有在应用Application中声明的业务组件,并且不需要再依赖任何功能组件。 ———————————————— 2)功能组件和Common组件(公共依赖的库) 功能组件是为了支撑业务组件的某些功能而独立划分出来的组件,功能实质上跟项目中引入的第三方库是一样的,功能组件的特征如下: 1、功能组件的 AndroidManifest.xml 是一张空表,这张表中只有功能组件的包名; 2、功能组件不管是在集成开发模式下还是组件开发模式下属性始终是: com.android.library,所以功能组件是不需要读取 gradle.properties 中的 isModule 值的;另外功能组件的 build.gradle 也无需设置 buildTypes ,只需要 dependencies 这个功能组件需要的jar包和开源库。 manifest.xml重复权限问题 > Task :module_bracelet:processDebugManifest /Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:50:5-69 Warning:Element uses-permission#android.permission.FLASHLIGHT at AndroidManifest.xml:50:5-69 duplicated with element declared at AndroidManifest.xml:48:5-69/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:23:9-27:56 Warning:activity#[email protected]:name was tagged at AndroidManifest.xml:23 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:23:9-27:56 Warning:activity#[email protected]:configChanges was tagged at AndroidManifest.xml:23 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:23:9-27:56 Warning:activity#[email protected]:theme was tagged at AndroidManifest.xml:23 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:29:9-39:20 Warning:provider#[email protected]:name was tagged at AndroidManifest.xml:29 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:29:9-39:20 Warning:provider#[email protected]:authorities was tagged at AndroidManifest.xml:29 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:29:9-39:20 Warning:provider#[email protected]:exported was tagged at AndroidManifest.xml:29 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml:29:9-39:20 Warning:provider#[email protected]:grantUriPermissions was tagged at AndroidManifest.xml:29 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml Warning:meta-data#[email protected]:name was tagged at AndroidManifest.xml:0 to replace other declarations but no other declaration present/Users/mac/android-bracelet/bracelet/module_bracelet/src/main/module/AndroidManifest.xml Warning:meta-data#[email protected]:resource was tagged at AndroidManifest.xml:0 to replace other declarations but no other declaration present
Android 中使用 fragment 提示error inflating class fragment
需要添加引用 android:id="@+id/frag_bracelet_debug" android:layout_width="match_parent" android:name="bracelet.yuedong.com.module_bracelet.fragment.BraceletFragment" android:layout_height="match_parent">
需要解决provider的名字重复的问题 app和module切换的时候,R文件总是不一样,切换,每次自己弄? 组件生命周期的管理: 看到了你的frame里的代码实现 明白了,目前管理组件生命周期貌似只有这种方式,通过获取到绝对类名,反射调用。 ——————————————— 我自己的参考: 简单入门:非常好的入门 https://blog.csdn.net/guiying712/article/details/55213884 https://www.jianshu.com/p/1c5afe686d75 非常不错的 https://www.jianshu.com/p/ba32488f9555 完美方案:demo不错 https://www.jianshu.com/p/1b1d77f58e84 弘扬的demo https://www.jianshu.com/p/00746e6fb48a
更多相关文章
- ionic3文件目录介绍
- [Android]使用化名(alias)功能防止相同资源的重复
- android从未安装的apk文件里获取信息(包信息,资源信息)
- 提高开发效率-使用Android Studio Template快速生成模板文件
- Android API开发之OpenGL开发之Android OpenGL显示STL模型文件
- Android界面组件基本用法
- android studio R文件找不到