在做sdk打包的时候,发现了有个问题,在sdk混淆之后,Recyclerview的不会接口不能使用,出现下面这样的问题:
E/InputEventReceiver: Exception dispatching input event.
E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
E/MessageQueue-JNI: java.lang.AbstractMethodError: abstract method "boolean android.support.v7.widget.RecyclerView$OnItemTouchListener.onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent)"
at android.support.v7.widget.RecyclerView.dispatchOnItemTouchIntercept(RecyclerView.java:2741)
at android.support.v7.widget.RecyclerView.onInterceptTouchEvent(RecyclerView.java:2787)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:417)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1808)
at android.app.Activity.dispatchTouchEvent(Activity.java:3198)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:379)
at android.view.View.dispatchPointerEvent(View.java:10258)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4500)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4365)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3905)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3958)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3924)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4051)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3932)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4108)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3905)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3958)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3924)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3932)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3905)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6309)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6283)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6244)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6415)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:187)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6379)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.qhqykj.analysis, PID: 14568
java.lang.AbstractMethodError: abstract method "boolean android.support.v7.widget.RecyclerView$OnItemTouchListener.onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent)"
at android.support.v7.widget.RecyclerView.dispatchOnItemTouchIntercept(RecyclerView.java:2741)
at android.support.v7.widget.RecyclerView.onInterceptTouchEvent(RecyclerView.java:2787)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2634)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2264)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:417)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1808)
at android.app.Activity.dispatchTouchEvent(Activity.java:3198)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:379)
at android.view.View.dispatchPointerEvent(View.java:10258)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4500)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4365)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3905)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3958)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3924)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4051)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3932)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4108)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3905)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3958)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3924)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3932)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3905)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6309)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6283)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6244)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6415)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:187)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6379)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
一看到这个问题,顿时懵逼了,怎么肥四,明明在debug版本是好好的?
百度一下,发现这类问题不多,而且还解释的不是很清楚。首先我们来分析一下,debug版本和release版本都是有混淆的
buildTypes {
/* 线上环境 */
release {
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "String", "API_HOST", "\"http://at.yunindex.com/\""//API Host
minifyEnabled true //是否混淆
//是否设置zip对齐优化
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
/* 预发环境 */
debug {
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "String", "API_HOST", "\"http://api.yunindex.com/\""//API Host
minifyEnabled true //是否混淆
//是否设置zip对齐优化
zipAlignEnabled true
//签名文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
很可能不是混淆的问题,难道是打包的问题?
import com.android.build.gradle.LibraryPlugin
import com.android.build.gradle.AppPlugin
def getPackageName() {
//输出AndroidManifes.xml文件的路径
println("siy-minifest:" + android.sourceSets.main.manifest.srcFile)
def androidManifest = new XmlSlurper().parse(android.sourceSets.main.manifest.srcFile)
def packageName = androidManifest['@package'];
println("siy-packageName:" + packageName);
return packageName;
}
def packageNameToPackagePath() {
String packagePath = "${getPackageName()}".replace('.', '\\');
println("siy-packagePath:" + packagePath);
return packagePath;
}
task makeJar(dependsOn: ['compileReleaseJavaWithJavac'], type: Jar) {
group "payeco"
description "Automatically generate the jar packages for the SDK"
//需打包的资源所在的路径集
def srcClassDir = [project.buildDir.absolutePath + "\\intermediates\\classes\\release"];
//初始化资源路径集
from srcClassDir
//输出class文件的路径
println("siy-srcClassDir:" + srcClassDir)
//去除路径集下部分的资源
exclude packageNameToPackagePath() + "\\BuildConfig.class"
//这里需要改为自己的包名,需要将包名aa.bb.cc改成aa\bb\cc
exclude packageNameToPackagePath() + "\\BuildConfig\$*.class"
exclude "**\\R.class"
exclude "**\\R\$*.class"
//只导入资源路径集下的部分资源
include packageNameToPackagePath() + "\\**\\*.class"
//整理输出的 Jar 文件后缀名
extension = "jar"
//最终的 Jar 文件名......如果没设置,默认为 [baseName]-[appendix]-[version]-[classifier].[extension]
archiveName = project.name + "-org-" + android.defaultConfig.versionName + "." + extension
}
task proguardJar(dependsOn: ['makeJar'], type: proguard.gradle.ProGuardTask) {
group "payeco"
description "Automatically generate the proguard jar packages for the SDK"
//Android 默认的 proguard 文件
configuration android.getDefaultProguardFile('proguard-android.txt')
//混淆的配置文件,我的是叫 proguard.cfg,也许有人叫 proguard-project.txt
configuration 'proguard-rules.pro'
String inJar = makeJar.archivePath.getAbsolutePath()
//输入未混淆jar包的路径
println("siy-inJar:" + inJar)
//输入 jar
injars inJar
//输出 jar
String outJar = inJar.substring(0, inJar.lastIndexOf(File.separator)) + "\\${makeJar.archiveName}".replace("-org-", "-")
//输出混淆jar包的路径
println("siy-outJar:" + outJar)
outjars outJar
//设置不删除未引用的资源(类,方法等)
// dontshrink
Plugin plugin = getPlugins().hasPlugin(AppPlugin) ?
getPlugins().findPlugin(AppPlugin) :
getPlugins().findPlugin(LibraryPlugin)
if (plugin != null) {
List<String> runtimeJarList
if (plugin.getMetaClass().getMetaMethod("getRuntimeJarList")) {
runtimeJarList = plugin.getRuntimeJarList()
} else if (android.getMetaClass().getMetaMethod("getBootClasspath")) {
runtimeJarList = android.getBootClasspath()
} else {
runtimeJarList = plugin.getBootClasspath()
}
for (String runtimeJar : runtimeJarList) {
println("siy-runtimejar:" + runtimeJar)
//给 proguard 添加 runtime
libraryjars(runtimeJar)
}
}
}
经过测试,通过执行makeJar任务打包的jar文件是没有问题,但是执行任务proguardJar打出来的包就有问题了,这两个任务的区别在于,makeJar没有对jar混淆,proguardJar对打包文件进行了混淆,那么,可以肯定,问题出在了混淆这一块。
分析一下异常的提示吧。RecyclerView$OnItemTouchListener.onInterceptTouchEvent问题出在这里了,没有在混淆文件中特别指定的话,那么类或者方法或者成员变量都是会被混淆的,然后OnItemTouchListener是RecyclerView的内部接口,是不是因为内部接口被混淆而不被识别了呢?
试试看再说吧,把实现OnItemTouchListener接口的类中实现的方法不混淆试试?
-keep class com.yindex.library.wrapper.YIndexOnItemTouchListenerWrapper{
public <methods>;
}
在proguard-rules.pro文件中加入这句,然后打包看看?
期待。。。
效果如何,试试就知道!!!!