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. <<<����: ����ע�ʹ������ 'org.jetbrains.kotlin.kapt3.base.ProcessorWrapper' ����֧�� source �汾 'RELEASE_7' ���� -source '1.8'ע: ARouter::Compiler The user has configuration the module name, it was [app]41 actionable tasks: 41 executed

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组件化项目搭建遇到的问题记录_第1张图片

以module-home为例,所有module必须在这里进行依赖。

Android组件化项目搭建遇到的问题记录_第2张图片

思路来源:

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) {

                throw  NullPointerException("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="@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'

https://shimo.im/docs/TG8PDh9D96WGTT8W

你可能感兴趣的:(Android组件化项目搭建遇到的问题记录)