由编译一个android开源项目, 学习如何解决AndroidStudio编译问题
关键字: android, studio, gradle, 编译失败, 编译异常, appcompat-v7, 23.0.0
https://www.cnblogs.com/poplartang/p/4981916.html
看过此文章能帮到你什么:
- 我在build.gradle里声明的compile三方库是什么规则.
- 我在build.gradle里声明的compile三方库, 具体内容下载到哪里去了.
- 编译库的时候的依赖到底是什么关联关系.
- 三方库下载下来了, 还出现出现编译失败问题, 怎么解决.
- 明明我配置的appcompat-v7版本是22.2.0(23.0.0以下), 编译的时候怎么非给我弄成23.0.0(或以上).
- appcompat-v7总是编译失败, 怎么解决.
- 在Android-23(6.0)及以后不支持HttpClient了(没有此API了), 我还要用这个库, 不降级sdk, 该怎么办.
- 解决编译问题的思路.
开森的用git检出一个github的好项目,想学习学习别人的代码,上来就给我报了个究极错误!
项目地址:
https://github.com/SkillCollege/SimplifyReader
一款基于Google Material Design设计开发的Android客户端, 采取的是MVP架构开发.
如果项目已经更新, 编译可能不按本文出错. 可以用我fork的包含编译错误的版本:
https://github.com/PoplarTang/SimplifyReader
[仅用来学习使用]
1. 找不到对应的样式资源:
把错误的原文贴到下边! (贴这做啥子? 这不有图吗?..) 为了方便被搜索爬虫爬到, 爬虫对我的截图懒得识别(猜测). 希望遇到这种问题的童鞋能搜到这里.
E:\Samples\2015\StudioProjects11\SimplifyReader\library\build\intermediates\exploded-aar\com.android.support\appcompat-v7\23.0.0\res\values-v23\values-v23.xml
Error:(2)Error retrieving parent for item:No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Inverse'.
Error:(2)Error retrieving parent for item:No resource found that matches the given name 'android:Widget.Material.Button.Colored'.
Error:Execution failed for task ':library:processReleaseResources'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException:Process'command 'C:\Develop\studio\sdk\build-tools\22.0.1\aapt.exe'' finished with non-zero exit value 1
2. 对应的values-v23.xml被打开之后, parent的资源找不到, 如下(注意最上边的文件)
就是这两个, 分别在5行, 24行.
<stylename="Base.TextAppearance.AppCompat.Widget.Button.Inverse"parent="android:TextAppearance.Material.Widget.Button.Inverse"/>
<stylename="Base.Widget.AppCompat.Button.Colored"parent="android:Widget.Material.Button.Colored"/>
解决方案:
方案一: 降低v7的版本到23以下, 21或22都可以支持Material Design效果
方案二: 调高编译版本到23及以上, 如果项目用到apache的HttpClient, 要单独添加对其的支持
以下为方案一:
我们要解决问题, 更要知道为什么! 问题解决思路:
现在我们清楚问题在于appcomat-v7里的主题资源无法识别. 此时我们回看编译配置文件build.gradle.
可以从Module(项目模块)图标上看的出来. 可运行项目是小手机图标 , 库项目是几本书
当前项目有3个Module -> app(主项目), library(引用库2), library_youku(引用库2)
相对于Project目录结构(看截图标题), 以Android的目录结构查看工程会更加直观(目录结构不深).
到底app有没有引用其他两个库Module, 要看他app的build.gradle配置.
build.gradle配置:
app这里引用了其libs目录下的所有jar, 两个友盟的三方库(首次需要联网), 以及 library和library_youku两个库Module
注意:这里的配置也可以在窗口上方中间位置的按钮查看.(快捷键是)
可以查看到对应配置界面:
这里并没有配置appcompat-v7相关的内容.那可以大胆的确定, 一定在library或library_youku这两个之中. (要不然还能配置到哪去?!)
打开library_youku的build.gradle:
library_youku这哥们配置的很少, 只有默认的libs和另一个库项目:library.
(看名字library_youku猜也知道库可能跟优酷相关, 名字越长, 功能越少嘛. 你自己感受一下: 哈佛大学, 哈尔滨机电数控模组工业职业技术培训学院)
打开library的build.gradle:
这个时候我们毫不意外地看到了一个大型项目不可或缺的简直丧心病狂到令人发指的一大堆引用库:
注意后边的注释是专门给列位加的, 我是怎么认识这些库的? 1.以前用过 2.我能在github搜到 3.我能在google,百度搜到.
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' // android官方support的v7包 compile 'com.android.support:cardview-v7:22.2.0'// android官方cardview-v7包, 给布局加个卡片式的背景. compile 'com.android.support:design:22.2.0' // android官方的material design风格包 compile 'com.jakewharton:butterknife:5.1.1' // 依赖注入框架butterknife, jakewharton大神作品 compile 'com.google.code.gson:gson:2.2.4' // json解析/序列化框架 compile 'me.gujun.android.taggroup:library:1.4@aar'// taggroup标签组. 不知道什么鬼, 没去搜 compile 'com.nineoldandroids:library:2.4.0'// 兼容3.0以前版本的属性动画库,jakewharton大神良心之作 compile 'com.readystatesoftware.systembartint:systembartint:1.0.3' // 配置4.4.4及以上沉浸式状态栏的库. compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3' // 经典的图片异步加载缓存库 compile 'com.github.chrisbanes.photoview:library:1.2.2'// 多点触控放大缩小图片的库 compile 'com.afollestad:material-dialogs:0.7.9.1'// 材料化对话框库 compile 'de.greenrobot:eventbus:2.4.0'// 事件总线库 compile 'com.squareup.okhttp:okhttp:2.4.0'// 网络数据加载库(推荐) }
快速过了一遍, 里边用到的网络加载, 数据解析, 图片处理库都是比较流行的三方库.
可是, 天杀的, 问题在于这里明明配置的是`appcompat-v7:22.2.0`而不是`appcompat-v7:23.0.0`
通过报错的文件可以看到的确是 appcompat-v7\23.0.0 版本下的
\SimplifyReader\library\build\intermediates\exploded-aar\com.android.support\appcompat-v7\23.0.0\res\values-v23\values-v23.xml
可以看到我当前编译的sdk版本是22
现在问题变成了两个方向:
1. 怎么降低appcompat-v7的版本为22.2.0 这样就不会出现sdk22无法支持的资源.
2. 直接提升sdk编译版本, 让appcompat-v7:23.0.0可以编译通过.
方向一:
降低生成的appcompat-v7的版本为22.2.0, 不让其出现无法识别的资源.
采用[折半查找]的战略思想.
a. 把所有library的依赖全删了
b. 将临时编译目录的下的所有文件删了, 避免复用混淆: \SimplifyReader\library\build\intermediates\exploded-aar\
c. 同步配置: 修改完配置后点右上角, 同步配置. 或屏幕上方中间按钮.
d. 思路: 相关的配置都删了, 看你还生不生成23.0.0 , 如果不生成了, 肯定就是这里边某个条目搞的鬼, 我再一半一半的删除.
果然\SimplifyReader\library\build\intermediates\exploded-aar\com.android.support下啥也没有了, 编译也不报那个错了.
这不行, 有点过了. 然后再把编译配置的后半部分删了,如下:
此时一同步, 的确出现的只是appcompat-v7/22.2.0而不是23.0.0, 那么里边也就不会出现values-v23.xml资源无法解析的问题了.
但是缺少了那些删除的依赖, 项目肯定报错找不着类.
此时分析: 问题一定出在剩下那个几个库中, 因为加了某个引用库而导致v7包版本被强制提升. 经过把剩余的部分折半删除. 可以定位到具体哪行配置出的问题. 一定要揪出你来!
有了思路, 一点一点来. 修改 -> 同步 -> 修改 -> 同步
果然, 找到了一行compile配置. 加了他,同步后的v7就提升为23.0.0, 不加他,同步后的v7 就还是我们配置的22.2.0
凶手就是他! 没错了:
compile 'com.afollestad:material-dialogs:0.7.9.1'
如果直接删掉此库, 代码里也不使用, 项目即可正常运行. v7便是的是22.2.0了. 但是就是一定要用呢?!
此时分析: 这个库本身的依赖配置可能将v7的版本设置的比较高. 如果没有配置文件, 怎么就平白无故因为你把我的整个项目v7版本提升了!
到jcenter找到这个库的所有相关文件和资料:
库中心网址: http://jcenter.bintray.com/
分析当前依赖的写法
1. com.afollestad:material-dialogs:0.7.9.1 是其在网站的定位方式
2. com.afollestad 表示其路径, 或者包名, 工程名称
3. material-dialogs 表示其工程下的项目/Module名称
4. 0.7.9.1表示material-dialogs项目的版本号
此时可以这么拼接:http://jcenter.bintray.com/com/afollestad/material-dialogs/
打开后我们可以看到如下内容
点开0.7.9.1可以看到里边有如下内容:
.javadoc为其文档包
.sources为其源码包
.aar为开发引用库 (用压缩工具解压即可看到内容)
.pom配置了该库所依赖的其他库
那么现在, 我要找到配置这个三方库同步后, 我电脑到底把这些东西下载到哪里了!
谁可以告诉我?! 答: 一个全局文件搜索软件: Listary, 或者Everything
搜什么? 搜0.7.9.1, 或者material-dialogs, 你要下载了文件名总不能随机取一个吧...
果然有, 在C盘Users用户目录下, 可以看到路径果然还包含了一些奇怪的生成的字符.
有三个关键的目录, 继续研究这三个目录:
注意路径里的poplar是我的用户名, 要改成自己的用户名, 感概一下目录好深.....
目录1:
E:\Samples\2015\StudioProjects11\SimplifyReader\library\build\intermediates\exploded-aar\com.afollestad\material-dialogs\0.7.9.1
此目录在工程项目的build文件夹中, 也就是说我们配置的compile 'com.afollestad:material-dialogs:0.7.9.1'会在build\intermediates\exploded-aar目录下保存其所有相关资源.
jars, res, 清单文件等.
目录2:
C:\Users\poplar\.gradle\caches\modules-2\files-2.1\com.afollestad\material-dialogs\0.7.9.1
里边有三个文件夹, 名字有一定的生成规则, 什么规则不重要:
分别保存了material-dialogs-0.7.9.1-sources.jar, material-dialogs-0.7.9.1.pom, material-dialogs-0.7.9.1.aar
刚才说到pom是保存的material-dialogs库的其他依赖配置文件, 待会我们就要修改的是他了!!!
目录3:
C:\Users\poplar\.gradle\caches\modules-2\metadata-2.15\descriptors\com.afollestad\material-dialogs\0.7.9.1
其中保存了编译目录2后的最终版本数据: 文件名为ivy.xml
接下来我们尝试修改目录2内部的material-dialogs-0.7.9.1.pom,
可以看到这里果然保存了v7相关的依赖23.0.0, 因为都是support包的, 所以一并改成22.2.0
截图如下:
然后重新同步编译, 依旧报错, 依旧是values-v23.xml里那两个资源找不到, 也就是说引用的仍旧是23.0.0版本
\SimplifyReader\library\build\intermediates\exploded-aar\com.android.support\appcompat-v7\23.0.0\
中仍旧是23.0.0的库.
那我们改的.pom配置到底通过什么生效了呢?
此时打开目录3里的文件:ivy.xml
此文件中可以清楚的看到appcompat-v7对应的版本是23.0.0
这里也印证了我们之前配置时候的写法com.afollestad:material-dialogs:0.7.9.1 -> org:name:rev -> 组织:名称:版本号
此文件ivy.xml并没有在jcenter的目录中出现过, 可以大胆猜想是在studio编译时生成的临时文件. 如果这个临时文件删了, 还可以重新生成.
我们的目的就是, 把所有出现23.0.0的, 全部搞成22.2.0 , 嗯, 就是这个原则! 就不信降不下来.
于是删掉这个临时生成的配置文件ivy.xml所在的根目录.重新同步gradle
------------------------------振奋人心的时刻----------------------------------
同步通过了!
这个错误不报了! 但是! 但是! 项目里的代码出了问题.
在项目的欢迎界面, 也就是SplashActivity里, 代码参数错误:
需要的是Context和String
而代码里只传了个String过去, 我们在131行, 第一个参数加上this传个context进去即可.
------------------------------振奋人心的时刻2!----------------------------------
重新同步! 同步通过! 编译通过! 运行通过!
冷静, 回去看看发生了什么!
目录3中的ivy.xml不出意外地变化了, rev都成了22.2.0
目录1: 项目的build目录中多出了22.2.0版本, 此时还保留了23.0.0. 如果把当前build目录下全部删除, 则仍旧会创建22.2.0目录.
结论:
1. 类似com.afollestad:material-dialogs:0.7.9.1这样的三方库, 可以配置自己的三方依赖.
2. 这些依赖库的三方依赖可以在material-dialogs-0.7.9.1.pom中手动修改. 重新同步可以生成ivy.xml, 从而降低整个项目的依赖版本
3. 当前Module最终使用的三方依赖, 如果build.gradle有重复配置. 取决于当前配置的所有库中版本最高那个.
4. 做三方依赖库的人最好把对其他依赖库的版本调整到自己可用的最小版本. 以免使用者的依赖库被提升.
5. 如果引用的三方依赖库手动降级后, 如果该库编译失败, 要么不用该库, 要么提升项目sdk编译版本.
吐槽:
1. 为什么作者不处理这个问题, 能直接编译通过?
当前项目编译版本设置的是sdk22, 如果出现23.0.0的appcompat-v7库肯定编译不通过的, 因为没有value-v23.xml对应的资源.
也就是说build文件中生成的可能就是配置的 compile 'com.android.support:appcompat-v7:22.2.0' 版本.他怎么生成的呢?
可能1: 作者的studio版本工具版本较低, 在低版本工具中不会自动提升依赖库
可能2: 依赖库com.afollestad:material-dialogs:0.7.9.1在作者创作时的material-dialogs-0.7.9.1.pom内配置的dependency版本在23.0.0以下.
我们在使用的时候, 去网上拿到的是更新后的内容.导致把整个v7版本提升.造成编译失败.我查看了0.7.9.0版本, pom下配置的同样是的23.0.0.
可能3: 作者的android support library版本太老, 没有更新到23以后, 所以没有自动提升到23.0.0. 截图是我的更新后的库
2. 为什么Google不考虑这个问题?
Google在每次你打开studio时, 都各种强烈建议升级studio, 升级sdk. 并不关心长城防火墙后的我们更新有多麻烦
不过近来国家防火墙好像已经给Android开发人员开了一道闸门, 用SDK Manager不用FQ就能直接更新google主机的内容了.
更多:
毕竟修改配置文件的方式官方肯定不推荐, 要不然怎么把配置文件目录藏得那么深.
不能每次都这么办, 标准的做法应该是提升自己的sdk编译版本为android-23 (6.0)及以上.
但是伴随着compileSdkVersion编译sdk版本和buildToolsVersion编译工具版本提升, 伴随着apache的HttpClient的无法调用.
下篇文章要解决的问题:
- 更新google的SDK及编译工具.
- 配置了三方库, 但下载不到三方库时, 怎么解决.
- 在Android23及以后支持HttpClient的两种方式.