项目处理问题遇到如下情况,引用第三方的 jar 包报出 ClassDefNotFoundException 错误导致 app 崩溃,双方沟通确认该类存在且排除工程未 clean,代码混淆导致等原因。
注意到编译 app 的时候提示了很多如下与正常情况下不一样的信息:
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/baidu/mapapi/SDKInitializer.class
...while processing com/baidu/mapapi/SDKInitializer.class
279 warnings
SDKInitializer 正是 ClassDefNotFoundException 报错的类。
百度搜索出现这个编译提示找到了问题出现的原因:第三方公司打包这个 jar 包使用的 jdk1.7 版本(大于 1.6),而我们编译 app 使用的是 1.6 版本,由于编译出的字节码版本不一致,导致无法转换成 android 虚拟机刻度的字节码,因此引用的 jar 包实际并未编译到当前 apk 中,程序运行的时候当然就找不到相应的类了。
公司编译服务器实际上配置了多个 jdk 版本,而且 android 编译是在设置环境变量的时候设置的 jdk 版本。编译 android4.4 使用的是 jdk1.6,而编译 android5.0 则使用的是 jdk1.7,这就涉及到了如何随时切换 jdk 版本。
先来看看如何设置 jdk 环境变量,百度搜索得到的答案多是修改~/.bashrc 或修改/etc/profile 文件一次性完成配置。我用 vi 打开这两个文件并未找到相应的 jdk 环境变量,但是使用 java -version 确实能看到默认的 jdk 版本。这就有了疑问,当前默认 jdk 软件的环境变量是在哪里配置的?
使用 which java 命令找到当前 java 可执行程序的位置
fordreamxin@compiler207:~$ which java /usr/bin/java
/usr/bin/目录下存放的多是用户安装的软件
fordreamxin@compiler207:~$ ll /usr/bin/java
lrwxrwxrwx 1 root root 22 Nov 13 06:18 /usr/bin/java -> /etc/alternatives/java*
alternatives 是一个 linux 下的多版本管理软件,利用它就可以实现 jdk 的版本切换,这点稍后再描述。先来 alternatives 目录地下看看有些什么东西。
fordreamxin@compiler207:/etc/alternatives$ ls java* java java.1.gz javac javac.1.gz javadoc javadoc.1.gz javah javah.1.gz javap javap.1.gz java_vm javaws javaws.1.gz
fordreamxin@compiler207:/etc/alternatives$ ll java
lrwxrwxrwx 1 root root 36 Nov 13 06:17 java -> /usr/lib/jvm/java-6-sun/jre/bin/java*
原来该目录下放置了很多软件的版本引用,从这里可以找到当前软件版本(jdk)的实际位置
fordreamxin@compiler207:/etc/alternatives$ ls /usr/lib/jvm/ java-1.7.0-openjdk-amd64 java-6-sun java-6-sun-1.6.0.26 java-7-openjdk-amd64
在/usr/lib/jvm 文件夹下时间存储了各个 jdk 版本的软件,而 alternatives 正是通过修改它的 java 引用达到版本切换的目的。
使用 alternatives 实现版本切换的方法如下:
1. 查看相应的 jdk 是否在 ubuntu 的 jdk 菜单里,查看:
update-alternatives --config java
update-alternatives --config javac
2.如果没有在菜单里可以如下方式添加:
update-alternatives --install /usr/bin/java java /usr/lib/jvm/java/jdk1.6.0_12/bin/java 300
update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java/jdk1.6.0_12/bin/javac 300
注意:jdk1.6.0_12 版本不同会有变动
3.sudo update-alternatives --config java
sudo update-alternatives --config javac
选择序号,回车即可;
4.然后 java -version,javac -version 查看当前 jdk 版本
但是使用 alternatives 需要 sudo 超级权限,也就是说这种切换是一种全局切换,同修改~/.bashrc 或/etc/profile 一样,一次操作,全局有效。如果没有超级权限怎么办?
设置环境变量 linux 提供了 export 命令,该命令的修改只对当前终端有效。
fordreamxin@compiler207:/ echo PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
上面的命令显示了当前的环境变量,也就是~/.bashrc 或/etc/profile 文件的内容,它表示了当前所有能够全局使用的所有软件或命令的环境变量,没有这些变量,我们不能在任意目录下使用很多命令或软件,这也是环境变量的意义所在。
通过如下命令可以在 $PATH 的开始或末尾添加 jdk 的环境变量(bin 目录下保存了 java, javac, javah 等可执行命令)
export PATH="/usr/lib/jvm/java-7-openjdk-amd64/bin":$PATH
export PATH="$PATH:/usr/lib/jvm/java-7-openjdk-amd64/bin/"
由于执行的时候总是从 $PATH 的开始搜索可执行文件的位置,所以如果环境变量中已经设置了一个 jdk,那么把新的 jdk 设置在 PATH 的开始才会有用。
export 的具体使用可参考它的使用手册。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于