Android Studio编译出的APK中一直包含android:debuggable="true"

最近遇到一个比较奇葩的事情,就是编译出来的 APKAndroidManifest.xml中的 application标签中一直包含 android:debuggable="true"。不管是 release版本,还是 debug版本,不管如何设置,最终生成的文件中的调试选项一直是处于开启状态。

一时间竟然有些无从下手的感觉。首先确认我们自己的配置文件是没有问题的,那么这个现象一定是引入了某个 aar中引入的 AndroidManifest.xml中存在这个 android:debuggable="true",导致 Android Studio在最终合并 AndroidManifest.xml文件的时候,把这个选项给合并进来了。

那么我们既然已经知道引入的地方,因此就只需要针对这种情况进行剖析即可了。

执行 gradlew build之后,我们在 app\build\intermediates\exploded-aar目录下面可以找到我们引入的全部的依赖的 aar。我们只需要逐个分析引入的 aar包的 AndroidManifest.xml文件即可。

那么比较奇葩,是奇葩在哪里呢? 正常情况下,我们引入一个 aar包,需要在 build.gradle中声明如下:

但是我们从真正的配置选项中看到的却是

按照一般的理解,我们如果没有设置 @aar,那么 Android Studio应该去下载对应的 jar包才对。但是我们从实际的编译过程中看到, Android Studio在没有指定 @aar的情况下,依旧默认去服务器上先尝试下载对应的 aar,只有当 aar找不到的时候才会去下载对应的 jar包。而恰好,我们服务器上面两者都是存在的。于是出现了乌龙事件,本来只是需要下载 jar包,结果却引入了一个莫名的 aar包。而这个 aar的开发同学又没有考虑到这种情况,以为用户只会用他提供的 jar包。
解决方法还是比较简单的,就是明确告知 Android Studio,我们需要的是 jar包,也就是增加 @jar。如下:

相关参考链接


Android Studio: Why is Release Build debuggable?

IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE,sockjs-1.1.1,stomp-1.2搭建基于Tomcat-7.0.68的WebSocket应用

接着上文IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE搭建基于Tomcat-7.0.68的WebSocket应用

上文的最后我们说到, WebSocket是需要定时心跳的,否则会在一段时间后自动断开连接,而更重要的是,不是所有的浏览器都支持 WebSocket,早期的 IE 10之前的版本就是不支持的,而这一部分的设备其实是不算少的,而 sockjs的出现,恰恰好来解决了这个问题。对于不支持 WebSocket的浏览器, sockjs使用了多种方式来兼容这种情况,包括使用长轮询等方式, Spring更是内建支持这种方式。

下面我们看如何在上篇文章的基础上,增加对于 sockjs的支持。

首先是 STOMP的文档官网地址 http://stomp.github.io/
代码的地址为https://github.com/jmesnil/stomp-websocket,项目下面的 lib/stomp.js就是我们想要的文件。也可以本站下载stomp.js.zip

接下来 sockjs的代码地址https://github.com/sockjs/sockjs-client,项目下面的 dist/sockjs-1.1.1.js就是我们想要的文件。也可以本站下载sockjs-1.1.1.js.zip

接下来我们把下载到的文件放到我们工程目录下面的 web-> resources-> javascript目录下面,如下图:

stomp-websockjs-resources

接下来,添加我们需要的 com.fasterxml.jackson.core:jackson-annotations:2.8.1, com.fasterxml.jackson.core:jackson-core:2.8.1, com.fasterxml.jackson.core:jackson-databind:2.8.1这三个 jar包,增加的方式参照上一篇中对于 javax.servlet:javax.servlet-api:3.1.0的操作方法。与上一篇的操作不同的是,这次添加的三个 jar包,都要放到编译完成后的 War包中。最后的结果如下图:
ToolsJacksonMaven

ToolsJacksonMavenWar

下面,我们开始进行代码的操作,我们在上篇文章中的 src-> Tools-> WebSocket中新增两个源代码文件 SockJsController.java, WebJsSocketConfig.java.如下图:

NewJavaSourcesForSockjs

其中的代码如下:
SockJsController.java

WebJsSocketConfig.java

然后修改 WebSocket.jsp

最后,我们修改 web-> WEB-INF-> web.xml,在其中增加

修改后的最终结果如下:

参考链接


 

Android Studio 2.1.3配置Robolectric-3.0,Powermock-1.6.5单元测试环境

Android Studio提供了比较方便的单元测试,但是由于 Android系统的限制( ClassloaderGoogle自己实现的, Powermock无法修改底层的 bytecode),目前 Powermock还没办法直接在设备上执行测试,但是我们代码中难免存在一些静态对象,需要测试的时候,只能求助于 PowermockRobolectric的组合。
具体的配置如下:
1.首先在需要测试的项目的 build.gradle中声明需要使用 PowermockRobolectric

2.定义测试基类,在基类中声明一些必备的设置
AbsRobolectricPowerMockTest.java

3.定义真正的测试子类
DeckardActivityTest.java

注意,参考链接中的内容不可完全相信,按照参考链接中的配置( Robolectric-3.1.2+ PowerMock-1.6.5),一般会遇到如下问题(看上去很怪异,其实是由于不同的 classloader同时加载了相同的类,导致尽管类名是相同的,但是依旧无法进行类型转换):

参考链接


Gradle本站镜像

使用 Android Studio开发,最痛苦的其中一项是 Maven下载数据缓慢,目前已经可以根据在Ubuntu 14.04 系统中的Apache Tomcat上部署Apache Archiva 2.2.1来使用本站的代理服务器的方式进行提速了。另一个痛苦的事情就是下载 Gradle工具包的速度异常缓慢了,不仅慢,而且还容易失败。
目前本网站已经提供了 Gradle工具包的下载代理,具体的操作就是把 services.gradle.org进行域名污染,指向本站的 IP地址 121.199.27.227
Windows下的解决方法为修改 C:\Windows\System32\drivers\etc下的 hosts文件,里面增加如下内容:

接着修改 Android Studio项目下的 gradle\wrapper\gradle-wrapper.properties文件,把其中的

修改为:

注意,上面的修改其实主要是把 HTTPS修改成了 HTTP,原因在于 HTTPS无法进行域名污染。

当然,另外一个比较简单的修改方式为,只要修改 distributionUrl为本站地址,更加省事:

目前本站提供的 Gradle工具包版本如下:

使用junit测试IntelliJ IDEA 2016.2建立的maven项目

maven project项目中引入 junit插件并不困难,只需要在 pom.xml中配置好依赖包即可( IDE环境下,依赖项会自动生成)。另外, test类文件需要按照 /src/main/java/的文件结构( main改为 test)。
pom.xml

如下图:

mavenjunitpath

Ubuntu 16.04下Tomcat 7.0.68启动服务时候报告“java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;”

在使用Ubuntu16.04 安装openjdk-7-jdk介绍的方式切换 Java1.7版本后,在进行代码调试的时候, Tomcat 7.0.68报告如下错误:

这说明 Ubuntu 16.04下的 Tomcat是在 Java 8环境下面编译的,尽管我们已经切换到 Java 7下面了,但是 Tomcat并不能很好的执行我们的 Java 7代码。这个时候的解决方法就是,编译代码的时候指定 Java 7,但是在 Tomcat执行的时候,指定使用 Java 8来运行。

参考链接


Java error java.util.concurrent.ConcurrentHashMap.keySet

IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE搭建基于Tomcat-7.0.68的WebSocket应用

先参照 IntelliJ IDEA 2016.1建立Strut2工程并使用Tomcat调试建立新的工程,一步一步操作,包括最后引用 Spring框架部分。

经过上面的操作, Spring-WebSocket的包应该已经被默认引入了,如下图所示:

spring-websocket-release-lib

这就意味着我们已经不需要再进行过多的额外配置了。

接下来,我们在 src-> Tools下面新建一个 WebSocket的目录,里面创建三个 Java文件。如下图:
WebSocketJavaSourceList

每个文件中的代码如下:
SystemWebSocketHandler.java

WebSocketConfig.java

WebSocketHandshakeInterceptor.java

由于我们使用了 Struts2导致我们的网络请求优先被 Struts2的拦截器拦截,而 Struts2又处理不了 websocket请求,结果直接返回了 404错误。因此我们需要替换掉默认的在 web.xml中定义的 Struts2的拦截器,要求 Struts2不处理 websocket请求。
我们在 src-> Tools下面新建一个 Filter的目录,下面创建一个名为 StrutsPrepareAndExecuteFilterEx.java的源代码文件,如下图:

StrutsPrepareAndExecuteFilterEx
具体的代码如下:
StrutsPrepareAndExecuteFilterEx.java

这时候的代码是无法编译通过的,原因是依赖的 javaxJar包不存在。此时,我们需要手工引入 javax.servlet:javax.servlet-api:3.1.0这个 Jar包。如下图:

ToolWebSocketProjectStructure

ToolWebSocketProjectStructureAddJars

ToolWebSocketProjectStructureAddJarsFromMaven

ToolWebSocketProjectStructureAddJarsFromMavenJavaxServerletApi3.1.0

ToolWebSocketProjectStructureAddJarsFromMavenJavaxServerletApi3.1.0Add

ToolWebSocketProjectStructureAddJarsFromMavenJavaxServerletApi3.1.0AddApply

还要注意,刚刚添加进入的 javax.servlet:javax.servlet-api:3.1.0这个 Jar包,我们只在编译期间使用,在运行时候,使用 Tomcat自己实现的那个同名 Jar包。也就是这个包是个 Provided,而不是 Compile关系,具体如下图:

ToolWebSocketProjectStructureKeepOutsideWar

接下来,修改 web.xml指定 Struts2的拦截器为我们定义的拦截器

修改为

经过上面的修改后,依旧是没办法进行网络访问的,原因是 web.xml中的 Spring拦截器并没有拦截 WebSocket的数据请求。

修改为

注意增加的

下一步,配置 Spring的配置文件 web-> WEB-INF-> dispatcher-servlet.xml增加配置信息类的扫描目录包含我们刚刚创建的 src-> Tools-> WebSocket的目录(缺少这一步会导致我们通过注解实现的配置信息类没有被自动加载,导致无法访问),修改后的内容如下:

最后,调用的页面的代码
WebSocket.jsp

最后的客户端显示效果如下图所示:
WebSocketJsp

注意:如此创建的 WebSocket是会在两三分钟后主动断开连接的,原因在于 WebSocket需要周期性的发送心跳报文来维持连接。后续我们会尝试使用s ockjs来实现自动发送心跳的逻辑。

具体的sockjs的接入方法,参考IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE,sockjs-1.1.1,stomp-1.2搭建基于Tomcat-7.0.68的WebSocket应用

Ubuntu16.04 安装openjdk-7-jdk

Ubuntu16.04的安装源已经默认没有openjdk7了,所以要自己手动添加仓库,如下:

# 1. oracle openjdk ppa source

# 2. oracle java jdk ppa source

JDK6 :

JDK 7:

JDK 8:

如果安装成功之后还是不能用可能不有多个版本,选的不对

选出正确的版本

参考链接


Ubuntu16.04 安装openjdk-7-jdk