Android组件化项目搭建遇到的问题记录

1. ARouter 的依赖问题
What went wrong:
Execution failed for task ':app:kaptDebugKotlin'.
A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
java.lang.reflect.InvocationTargetException (no error message)
Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
Get more help at https://help.gradle.org
BUILD FAILED in 4s
?: ARouter::Compiler >>> AutowiredProcessor init. << Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
解决办法:回到Arouter官方的使用上,认真研读注意事项,找到原因。
1.ARouter中的依赖注意事项
在Base module中添加配置
comple 'com.alibaba:arouter-api:1.1.0'
annotationProcessor 'com.alibaba:arouter-compiler:1.1.1'
2. 在各个模块中的build.gradle中的defaultconfig属性中加入:
Java:
?```groovy
javaCompileOptions{
annotationProcessorOptions{
arguments = [moduleName:project.getName()]
}
}
Kotlin:
kapt {
arguments {
// 路由框架译配置
// module名称
arg("AROUTER_MODULE_NAME", project.getName())
// 是否生成路由文档,"enable":生成文档,其他字符串不生成路由文档
arg("AROUTER_GENERATE_DOC", "enable")
}
}
在每个模块的dependencies属性需要Arouter apt的引用,不然无法在apt中生成索引文件,无法跳转成功
旧版本的Arouter引用:
dependenceis{
annotationProcessor 'com.alibaba:arouter-compiler:1.1.1'
}
新版本中的Arouter中引用:
// 路由框架注释处理器
kapt "com.alibaba:arouter-compiler:$arouter_compiler_version"
Arouter中的官方中对kotlin中的引用说明:
// 可以参考 module-kotlin 模块中的写法
apply plugin: 'kotlin-kapt'
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
compile 'com.alibaba:arouter-api:x.x.x'
kapt 'com.alibaba:arouter-compiler:x.x.x'
...
}
What went wrong:
Could not initialize class org.codehaus.groovy.runtime.InvokerHelper
解决办法:
更新gradle版本号 到6.3,之前的版本号是gradle-5.6.4-all
改为:gradle-6.3-all.zip
https://stackoverflow.com/que...
Please make changes as per below to resolve this error.
Install Java SDK version: 14 or above.
JDK Download link: https://www.oracle.com/java/technologies/javase-jdk14-downloads.html
In gradle-wrapper.properties please use grade version 6.3 or above.
For e.g:distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
2.其他编译问题:
No such property: variantConfiguration for class:
com.android.build.gradle.internal.variant.ApplicationVariantData
思路一:参考stackoverffow中的方案,修改gradle版本号,未果。
A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
原因:ARouter编译问题:
> Task :app:kaptCtestKotlin FAILED
注: ARouter::Compiler >>> AutowiredProcessor init. <<<警告: 来自注释处理程序 'org.jetbrains.kotlin.kapt3.base.ProcessorWrapper' 的受支持 source 版本 'RELEASE_7' 低于 -source '8'注: ARou
ter::Compiler The user has configuration the module name, it was [app]
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:kaptCtestKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
> java.lang.reflect.InvocationTargetException (no error message)
解决方案:回到Arouter中有关kotlin的引入时,发现:
需要这样引入:注意版本号以最新的为准,版本号不一样的。
// 路由框架注释处理器 https://github.com/alibaba/ARouter
kapt "com.alibaba:arouter-compiler:1.2.2"
api 'com.alibaba:arouter-api:1.5.0'
问题来了,组件化中如何引入?
默认启动问题
06/18 15:40:14: Launching 'app' on HUAWEI HLK-AL00.
Could not identify launch activity: Default Activity not found
Error while Launching activity
解决办法:AS清除缓存、Sync、解决模块中的资源引入问题后,最后发现 在组件中引用出了问题。
必须记得在宿主app中引用相应的模块。
如果出现这个错误日志:
Error: null, Cannot fit requested classes in a single dex file (# methods: 70124 > 65536)
解决文案:都是由依赖第三方库jar包引发的,可以通过修改app的build.gradle文件解决该错误。
添加依赖:
dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
在defaultConfig中添加以下属性
multiDexEnabled true
3. 编译阶段 注册界面没有发现实现类
ARouter::Register >>> No class implements found for interface:com/alibaba/android/arouter/facade/template/IInterceptorGroup
项目中的问题表现:获取不到Fragment 中的实例,跳转失败,无法启动首页。
解决办法:通过查阅资料,发现所依赖的模块没有在App宿主中进行依赖。
Android组件化项目搭建遇到的问题记录
文章图片
以module-home为例,所有module必须在这里进行依赖。
Android组件化项目搭建遇到的问题记录
文章图片
思路来源:
There's no router matched!
在组件化开发过程中,我在宿主App模块引用模块C中的Activity,一直不能成功,界面及日志提示"W/ARouter::: ARouter::There is no route match the path [/xxx/xxx], in group xxx"
最终定位原因是需要在宿主App的build.gradle中,把需要路由的模块(上例中的模块C)引入进来。
在组件化开发中,各模块建议不要有依赖关系。宿主App在打包编译时可依赖各组件,组件之间可以使用ARouter进行界面跳转。上例中模块c和d之间无依赖关系,但是再宿主app中可以进行跳转。
4.网络请求
目标IP :110.184.70.43
执行时间 :0.085(秒)
当前状态 :200
返回状态 :200 null
Request Header:
Content-Type : application/x-www-form-urlencoded
Content-Length : 6
Response Header:
Transfer-Encoding : chunked
Connection : close
Date : Fri, 08 May 2020 06:45:27 GMT
Content-Type : application/json; charset=UTF-8
请求中的Content-Type 设置
1、application/x-www-form-urlencoded; charset=utf-8
查看相关文档发现,这种Content-type类型是以form表单的形式提交数据的是基于uri的percent-encoding编码的,所以body中的数据会以key=values的形式进行序列化,而这个编码的过程中,一些特殊符号会通过URL转码转成如4%D3%3F。。。等形式,这就导致了我们前面出现了json数据被做了这样的处理,因为默认情况下okhttp的Content-type默认就是application/x-www-form-urlencoded,这就不难解析为什么后台以流的形式读取数据的时候拿到的数据多了个content=,并且被编码了。
2、application/json; charset=utf-8
这种Content-type的编码方式现在是非常流行的,如果你在请求的时候使用抓包工具进行抓包,你会发现,请求体里面显示的内容是一个标准的json串,而不会像经过URL转码后的数据那样。
http协议POST请求头content-type主要的四种取值
content-type一般只存在于Post方法中,因为Get方法是不含“body”的,它的请求参数都会被编码到url后面,所以在Get方法中加Content-type是无用的。
四种常见的 POST 提交数据方式
application/x-www-form-urlencoded
multipart/form-data
application/json
text/xml
5.混淆相关
写给 Android 开发者的混淆使用手册
6.打包问题相关
Task :app:minifyReleaseWithR8 FAILED
E:projectPandaappmultidex-config.pro: R8: Failed to read file: E:projectPandaappmultidex-config.pro
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:minifyReleaseWithR8'.
com.android.tools.r8.CompilationFailedException: Compilation failed to complete
7.阿里一键登录时因为第三适配框架引发的问题
2020-05-12 17:35:51.039 10332-10466/com.tywj.buscustomerapp E/AuthSDK: java.lang.IllegalStateException: Not in applications main thread
at me.jessyan.autosize.utils.Preconditions.checkMainThread(Preconditions.java:113)
at me.jessyan.autosize.AutoSizeCompat.autoConvertDensity(AutoSizeCompat.java:139)
at me.jessyan.autosize.AutoSizeCompat.autoConvertDensityBaseOnWidth(AutoSizeCompat.java:112)
at me.jessyan.autosize.AutoSizeCompat.autoConvertDensityOfGlobal(AutoSizeCompat.java:57)
at com.tywj.buscustomerapp.common.view.base.MyBaseActivity.getResources(MyBaseActivity.kt:64)
at com.mobile.auth.gatewayauth.utils.b.c(Native Method)
at com.mobile.auth.gatewayauth.utils.SupportJarUtils.startActivityForResult(SupportJarUtils.java:26)
at com.mobile.auth.gatewayauth.a.g(Native Method)
at com.mobile.auth.gatewayauth.ctcc.a.j(Native Method)
at com.mobile.auth.gatewayauth.ctcc.a.a(Native Method)
at com.mobile.auth.gatewayauth.PhoneNumberAuthHelper.b(Native Method)
at com.mobile.auth.gatewayauth.PhoneNumberAuthHelper.a(PhoneNumberAuthHelper.java:53)
at com.mobile.auth.gatewayauth.PhoneNumberAuthHelper$2.a(PhoneNumberAuthHelper.java:1202)
at com.mobile.auth.gatewayauth.utils.h$a.run(Native Method)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
解决方案:该界面取消适配
集成阿里一键登录布局问题
2020-05-15 16:59:23.808 9430-9430/com.tywj.buscustomerapp E/AuthSDK: java.lang.IllegalStateException: ivTaobao must not be null
at com.tywj.buscustomerapp.LoginAuthActivity$configLoginTokenPort$1.onViewCreated(LoginAuthActivity.kt:182)
at com.mobile.auth.gatewayauth.ui.a.(PnsView.java:27)
at com.mobile.auth.gatewayauth.ui.a.(PnsView.java:18)
at com.mobile.auth.gatewayauth.LoginAuthActivity.h(Native Method)
at com.mobile.auth.gatewayauth.LoginAuthActivity.d(Native Method)
at com.mobile.auth.gatewayauth.LoginAuthActivity.onCreate(Native Method)
at android.app.Activity.performCreate(Activity.java:7232)
at android.app.Activity.performCreate(Activity.java:7221)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2964)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3119)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1839)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6864)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
2020-05-15 16:59:23.906 9430-9430/com.tywj.buscustomerapp E/xxxxxx: onTokenFailed:{"code":"600023","msg":"加载自定义控件异常","requestCode":0,"vendorName":"CTCC"}
解决办法 :kotlin中不能直接用,需要用findById(R.id.xx){}
8. 混淆后出现的问题
Caused by: java.lang.NoSuchFieldException: No field mObservers in class Landroidx/lifecycle/LiveData; (declaration of 'androidx.lifecycle.LiveData' appears in /data/app/com.tywj.buscustomerapp-d3FzmCWoaSzUUxOl777Wtg==/base.apk!classes2.dex)
at java.lang.Class.getDeclaredField(Native Method)
at com.tywj.buscustomerapp.common.bus.LiveDataBus$BusMutableLiveData.a(LiveDataBus.kt:136)
at com.tywj.buscustomerapp.common.bus.LiveDataBus$BusMutableLiveData.a(LiveDataBus.kt:127)
at com.tywj.buscustomerapp.common.bus.LiveDataBus.a(LiveDataBus.kt:28)
at com.tywj.buscustomerapp.user.UserFragment.l(UserFragment.kt:44)
at com.tywj.lib.core.common.view.a.onActivityCreated(BaseFragment.kt:54)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2619)
at androidx.fragment.app.h.a(FragmentManagerImpl.java:904)
at androidx.fragment.app.h.l(FragmentManagerImpl.java:1238)
at androidx.fragment.app.a.e(BackStackRecord.java:434)
at androidx.fragment.app.h.a(FragmentManagerImpl.java:2079)
at androidx.fragment.app.h.b(FragmentManagerImpl.java:1869)
at androidx.fragment.app.h.c(FragmentManagerImpl.java:1824)
at androidx.fragment.app.h.r(FragmentManagerImpl.java:1727)
at androidx.fragment.app.h.d(FragmentManagerImpl.java:2663)
at androidx.fragment.app.h.g(FragmentManagerImpl.java:2613)
at androidx.fragment.app.d.a(FragmentController.java:246)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:542)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1392)
at android.app.Activity.performStart(Activity.java:7260)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3008)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1839)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6864)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
2020-05-19 11:23:17.105 1340-1656/? E/InputDispatcher: channel 'd045c90 com.tywj.buscustomerapp/com.tywj.buscustomerapp.launch.SplashActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
private fun disableSticky(observer: BusObserverWrapper) {
if (observer.isSticky || observer.isWithoutActiveStatus) {
return
}
val classLiveData = LiveData::class.java
val fieldObservers = classLiveData.getDeclaredField("mObservers")
fieldObservers.isAccessible = true
val objectObservers = fieldObservers.get(this)
val classObservers = objectObservers.javaClass
val methodGet = classObservers.getDeclaredMethod("get", Any::class.java)
methodGet.isAccessible = true
val objectWrapperEntry = methodGet.invoke(objectObservers, observer)
var objectWrapper: Any? = null
if (objectWrapperEntry is Map.Entry<*, *>) {
objectWrapper = objectWrapperEntry.value
}
if (objectWrapper == null) {
throwNullPointerException("Wrapper can not be bull!")
}
val classObserverWrapper: Class = objectWrapper.javaClass.superclass!!
val fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion")
fieldLastVersion.isAccessible = true
val fieldVersion = classLiveData.getDeclaredField("mVersion")
fieldVersion.isAccessible = true
val objectVersion = fieldVersion.get(this)
fieldLastVersion.set(objectWrapper, objectVersion)
}
}
解决办法:更换最新的消息组件
9.关于键盘遮挡或上面的布局向上移动的问题。

android:name="com.tywj.navigation.map.NavigationSelectedAddress"
android:windowSoftInputMode="adjustPan"/>
添加键盘属性。
adjustPan:当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。
adjustResize:该Activity总是调整屏幕的大小以便留出软键盘的空间。
10.上下切换动画实现
android 动画调换上下布局(类似导航起始地址和导航目的地切换)
public void swapViewUpDown(int upViewId, final int downViewId) {
final View upView = (View) findViewById(upViewId);
final View downView = (View) findViewById(downViewId);
upView.animate().translationYBy(upView.getHeight()).setDuration(ANIMATION_DURATION)
.setInterpolator(new BounceInterpolator());
downView.animate().translationYBy(-downView.getHeight()).setDuration(ANIMATION_DURATION)
.setInterpolator(new BounceInterpolator());
}
4种动画插值器
OvershootInterpolator:冲过了头回滚一点的效果
AnticipateInterpolator:出发前先后退一步再前冲的动画效果
AnticipateOvershootInterpolator:以上两种的结合
BounceInterpolator:自由落地后回弹的效果
11.ImageView中旋转180度
使用场景:用代码控制旋转,实现动画和减少资源图片文件使用。
使用ImageView自带的旋转方法
android:src="https://www.it610.com/article/@drawable/common_back"
android:layout_centerInParent="true"
android:id="@+id/lv_common_return"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="180" />
目的,对于规则的图片,不需要相同的图片切两次,可以直接用翻转实现。关键代码:
android:rotation="180"
代码实现
image.setPivotX(image.getWidth()/2);
image.setPivotY(image.getHeight()/2); //支点在图片中心
image.setRotation(90);
也可以用动画实现:
object RotateUtils {
/**
* 根据当前的状态来旋转箭头。
*/
fun rotateArrow(arrow: ImageView, flag: Boolean) {
val pivotX = arrow.width / 2f
val pivotY = arrow.height / 2f
var fromDegrees = 0f
var toDegrees = 0f
// flag为true则向下
if (flag) {
fromDegrees = 0f
toDegrees = 180f
} else {
//向上
fromDegrees = 180f
toDegrees = 360f
}
//旋转动画效果参数值 旋转的开始角度旋转的结束角度pivotX x轴伸缩值
val animation = RotateAnimation(
fromDegrees, toDegrees,
pivotX, pivotY
)
//该方法用于设置动画的持续时间,以毫秒为单位
animation.duration = 200
//设置重复次数
//animation.setRepeatCount(int repeatCount);
//动画终止时停留在最后一帧
animation.fillAfter = true
//启动动画
arrow.startAnimation(animation)
}
}
另一种动画 :可以使用ImageView配合属性动画实现
rotateImage.animate().rotation(90);
普通动画
Animation rotateAnimation= new RotateAnimation(lastAngle, progress, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1);
rotateAnimation.setFillAfter(true);
rotateAnimation.setDuration(50);
rotateAnimation.setRepeatCount(0);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateImage.startAnimation(rotateAnimation);
参考:Android UI之ImageView旋转的几种方式
12.华为手机安装app无启动图标
问题原因:可能是在LearnCanry引入产生,正式打包后问题依然存在。而oppo、小米手机安装后显示正常。
解决办法:华为手机权限处理后,将主题设置为华为的的主题后,可见。
13.组件化之间的 xml资源文件问题
如果有相同的布局等文件,一定要删除重复的或其他命名,否则 Kotlin中初始化时会找不到。提示为null
java.lang.IllegalStateException:xxx(etFeedback) must not null
原因:user-center组件化时有重复的资源,冲突后找不到出错。
14.阿里一键登录时oppo手机在压缩打包后无法唤醒登录页
通过日志分析:发现无法找到资源文件,而阿里官网却没有说明,只得通过日志一步一步去定位。
"R.drawable.umcsdk_return_bg"
"R.drawable.umcsdk_login_btn_bg"
"R.drawable.umcsdk_uncheck_image"
最后将umcsdk相关的加入白名单,不压缩,问题得以结局。
//白名单
whiteList = [
//这里的资源在部分手机(viVo、小米)中无法唤醒,是友盟的资源文件混淆了,分析日志得出结论
"R.drawable.umcsdk*"
]
注意:此处引入了Android资源混淆工具
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.18'
【Android组件化项目搭建遇到的问题记录】https://shimo.im/docs/TG8PDh9D96WGTT8W

    推荐阅读