Volley 开启对Https的支持,并且忽略对Hostname的检查

直接上代码:

mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(),
new HurlStack(null, newSslSocketFactory()));

详见这篇文章,这里不在重复.

但仍有报错,

java.io.IOException: Hostname ... was not verified

证书的Hostname与实际的不匹配,历史原因不能修改证书。

别外的解决方法是让Https忽略对Hostname的Verify。但对Volley来说尝试了多种方法都不行。

之前一直使用的是apache的SSLSocketFactory,org.apache.http.conn.ssl.SSLSocketFactory

可以调用 setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER)来进行设置。

但Vollley中HurlStack使用的是 javax.net.ssl.SSLSocketFactory,没有找到可以进行设置的地方。

无耐之下,只能修改Volley的原代码,基于官方6.11日版本:

修改com.android.volley.toolbox.HurlStack的openConnection()

编译并导入测试可以正常通信,如相关资料所说,此法仅用于测试,正式使用还是很危险的。

// use caller-provided custom SslSocketFactory, if any, for HTTPS
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
    ((HttpsURLConnection)connection).setHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String arg0, SSLSession arg1) {
            return true;
        }
    });
    ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
}

Paho Tls 双向认证

Eclipse的Paho开源项目,默认TLS只支持对MQTT服务器的单向认证,官方Service中己集成相关方法:

MqttConnectOptions conOpt;

MqttAndroidClient client;

uri = “ssl://”;

InputStream ins = this.getResources().openRawResource(R.raw.ca);//ca.bks是由ca.crt通过Keytool工具导出的

String keypassword = “123456”;

conOpt.setSocketFactory(client.getSSLSocketFactory(ins, keypassword));

实现双向认证需要自己生成SocketFactory,具体代码如下:

MqttConnectOptions conOpt;

MqttAndroidClient client;

uri = “ssl://”;

InputStream ins = this.getResources().openRawResource(R.raw.ca);//ca.bks是由ca.crt通过Keytool工具导出的

InputStream clientIns = this.getResources().openRawResource(R.raw.client); //client.p12是由clinet.crt与client.key用openssl 导出的

String keypassword = “123456”;

conOpt.setSocketFactory(get2SSLSocketFactory(clientIns,ins,keypassword,keypassword));

… …

public SSLSocketFactory get2SSLSocketFactory(InputStream clientKeyStore,

           InputStream ServerKeyStore, String clientPassword, String ServerPassword)

           throws MqttSecurityException {

       try {

           SSLContext ctx = null;

           SSLSocketFactory sslSockFactory = null;

           // for server key store

           KeyStore ts;

           ts = KeyStore.getInstance(“BKS”);

           ts.load(ServerKeyStore, ServerPassword.toCharArray());

           TrustManagerFactory tmf = TrustManagerFactory.getInstance(“X509”);

           tmf.init(ts);

           // for client key store

           KeyStore kts = KeyStore.getInstance(“PKCS12”);

           kts.load(clientKeyStore, clientPassword.toCharArray());

           KeyManagerFactory keyManager = KeyManagerFactory.getInstance(“X509”);

           keyManager.init(kts, clientPassword.toCharArray());

           // init

           ctx = SSLContext.getInstance(“tlsv1”);

           ctx.init(keyManager.getKeyManagers(), tmf.getTrustManagers(), null);

           sslSockFactory = ctx.getSocketFactory();

           return sslSockFactory;

}…

   }

其中关键在PKCS12格式证书的生成,需要使用client的crt与key

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

之前走了很多弯路,在这个地方使用与生成ca.bks的方法来生成client证书,总是报错:

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x75c72988: Failure in SSL library, usually a protocol error

error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure (external/openssl/ssl/s3_pkt.c:1256 0x7851af18:0x00000003)

SSL/TLS的加密码比较复杂,各种证书格式,加上需要跨平台通讯,问题比较多,在与Mosquito服务器通讯时,发现Tls的版本不对也会报错,

MqttException (0) – javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7861ada8: Failure in SSL library, usually a protocol error

error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0x71e78cf8:0x00000000)

Paho项目貌似只支持到Tlsv1,而服务器用的是Tlsv1.2,导致握手失败。

Paho使用ANT编译出错与Maven

Paho的官方库中克隆下来的mqtt client导入Eclipse竟然编译不过,给Paho Project提了一个BugBug 440052 – Paho mqttv3 client can’t be build sucessfully by defaul.

这么明显的错误,项目人员不可能不知道吧,并且他们有Daily Build,在官网都有每日编译后的版本发布。

怀疑是不是自己的编译环境有问题,仔细看了看,工程中发现Pom.xml,之前一直没接触过Maven,看了些资料发现,整个Paho项目应该是用Maven构建的,所以自己在导入Eclipse后使用ANT编译出了问题(但这的解是个问题,看官方的答复)

Maven的介绍参考这篇文章:Maven 2.0:编译、测试、部署、运行

总结下我所了解的项目编译构建工具:

1  

Make

MakeFile

C/C++

2

ANT

Build.xml

Java

3

Maven

Pom.xml

Java

4

ADT

AndroidManifest.xml

Android

5

VSTS

*.sln
*.suo

C#,VB

6

gradle

build.gradle

Java

以上可以看出来,这些工具的本质是一样的,编译规则,文件关连及项目相关信息的存储,使用工具进行编译,只是各有各的优点且都在不断进化。

Android端直接使用MQTT协议与第三方PUSH服务对比

AndroidMQTT使用基于EclipsePaho项目库,Broker使用网上免费的Mosquito服务器。第三方使用Baidu云推送。从以下四个方面对比:

一,到达率对比
         在相同的网络环境(WIFI/GPRS),两者基本都能够及时收到,延迟在1S之内,测试中偶现有延时送达的,暂没有发现丢包或收不到的情况.

          二者在被进程管理软件杀死后,默认都无法自动重启,不能继续与服务器进行沟通。要做到死后重生,需要采用特殊处理,如提高Service的优先级,设置Service在内存中的驻留方式,在ServiceStop函数当中重新启动等方法。

二,所消耗的流量对比

        Android端设置心跳间隔为5分钟,测试一个小时,推送6次信息,每次平均20Bytes,检测软件上看共消耗2.3KB,按这个流量算,一个月约需要消耗1.6M的流量。

        Baidu云推送,官方给的数据是,空载流量0.8-1.2M/月。

三,功耗对比

       测试环境:使用同一台手机,仅开启Wifi(排除电话,短信等通知信息对电流的影响),设置心跳间隔为5分钟,测试其间平均发送6次推送,结果如下:

E760(Android4.0)

底电流(平均值)

10分钟平均电流(测试3轮求平均)

30分钟平均电流(测试3轮求平均)

仅开Wifi待机

4.2mA

7.2mA

6.7mA

仅开启MQTT

4.2mA

7.7mA

7.6mA

仅开启百度云推送

4.2mA

7.8mA

7.3mA

    从对比结果看,开启MQTT或云推送,对平均电流的影响不大,平均每日耗电约12~14mAh. 网上资源显示实测移动设备空载耗电每日15-50mAh。WifiGPRS3G不同网络环境可能会稍有差距。

综上:使用MQTT与第三方Push在流量及功耗上没有太多差距,测试过程中MQTT能与服务器建立稳定的长链接,并且从查找的资源看AndroidAPP基本上都是用MQTT直接做Push服务的,没有例子同时与第三方Push联合使用的,因此如果能够自建MQTT服务器的话,完成可以自己实现Push服务。

Android端第三方Push服务对比

对比了现在比较流行的几款第三方Push服务,对比结果汇总如下:

 

响应速度(平均延迟)

到达率(百分比)

官方文档支持

第三方帐号

代表客户

综合评价

极光

1s

99%

支付,需要绑定

去哪,中国电信

 

百度

1s

99%

较少

支持,需要绑定CID

糗事百科

 

个推

支持,需绑定个推CID

新浪,墨迹,PPTV

 

智游

收不到

收不到

支持

 

响应速度与到达率为平均值,不同的地方,时间段,网络接入方式可能结果不同。目前测试的地点有青岛,杭州,网络有EGDA,WIFI。对比测试在同一手机,同一网络环境下进行。

测试过程中均有发现,无法收到Push消息及延迟问题,极光与百度会好些,发生的概率较小。

这些第三方都有自己的帐号系统,要做到准确推送,需要把这些第三方的帐号与咱们的帐号匹配。

    以JPush为例这个绑定有两个基本思路:
      1. 把绑定关系保存到 JPush 服务器端
      2. 把绑定关系保存到开发者应用服务器中
    前者,就是这里要说到的:别名与标签的功能。
    后者,则是 JPush 提供的另外一套 RegistrationID 机制。这套机制开发者需要有应用服务器来维护绑定关系,不适用于普通开发者。

综上,使用第三方推送服务,优势是使用简单,有较完善的SDK。缺点是:服务器端不可控,且需要自己做与第三方的帐号绑定。

欧瑞博智能家居套件试用报告

     周未试用了两天欧瑞博智能家居套件,包括一个WiFi智能插座,一个WiFI智能遥控器:

优点:1.入网还算便捷,长按插座或遥控器上的开关,红灯闪烁进入配置模式。

         2.多设备免重复添加,即只需一台手机配置,同一网络下的其它手机直接搜索即可。

         3.设备断电,移动位置仍可以继续使用,不用重复配置。

         4.设备反映及时,按下基本同时完成设备操作。

         5.免用户注册与登陆即可实现远程控制

 

缺点:1.APP上的功能太少,只有设备列表与模式控制,并且UI美观不够,还可以做的更人性化。

         2.IOS上的APP问题很多,经常丢失链接。

         3.UI给用户的感觉比较迟钝,像按下按钮调整电视音量,我要连续减少音量,但每按一次,UI上会有个小圈在转,不连续感觉。

         4.智能插座的动静太大,每次开关都有“啪啪”声,很不安全的感觉。

         5.远程控制功能没有介绍,都不知道有此功能。免登陆很方便,但有安全隐患。

背后的原理:

      优缺点大家讨论了很多,这里深入分析下这些设备的实现原理,以插座为例:

1.闪联功能:即配置入门功能的实现,长按插座开关,进入红光快闪状态,此时插座上的Wifi应该是处理搜索模式,搜索一固定的WIFI AP热点,此热点就是客户端APP进入配置模式后打开的,当插座找到此AP后,会获取把要链接的WIFI名称及密码(在配置的时候用户在APP上输入的),之后配置完成,插座就能链接到家里的Wifi路由上了。之后就是普通的Wifi通信。

2.免登陆远程控制功能:每个设备如这个插座都有一个唯一的UUID,配置成功后,此设备便与欧瑞博的服务器通过Wifi建立长链接,这样,当用户离开家后,如通过3G再控制此插座,就会在服务器上查找对应的UUID,找到后,把控制命令下发到插座。这样的确很方便使用,但安全隐患很大,理论上知道了此UUID,就任何人可以随便控制了,也没有用户名密码的保护。

我们最近也在做一款智能控制套件,功能要“高大上”些,以下几个方面觉得可以吸取下:

        1.入网配置,做到比较快捷方便,不要为难用户。我们上一个U+项目,采用的是扫描二维码配置入网,先扫描后仍需要按键入网,流程上不如欧瑞博的简单。

        2.反应速度,我们要通过云实现远程控制,设备能不能及时反应有待考验。

Android与Server的交互方式

Android客户端与服务器交互方式,基于两种通信协议,四类通信方式,如下图:


【Socket与HTTP两种连接协议的区别】

1.HTTP连接使用的是”请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。

2.socket是可以监听,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。保持客户端与服务器数据的实时与同步。

【四种连接方式的区别】

1.Socket,Android端SDK原生支持,服务器端无论是Java还是.NET都有接口,需要注意的地方与普通基于Socket网络编程的一样。

2.Http/HttpClient, Android端SDK原生支持,服务器端也无其它要求,ASP,JSP,PHP都能够处理,典型的框架如SSH-JSON。Java技术的服务器主要使用HttpServlet,.net技术的服务器对应HttpHandle,但处理起来没有那么Java那么直观。Http/HttpClient可采用的数据格式协议可以是简单的String类型,也可以是JSON或XML。

3.xml rpc是使用http协议做为传输协议的rpc机制,使用xml文本的方式传输命令和数据。Android本身并不支持XML-RPC协议, 需要下载相关工具, http://code.google.com/p/android-xmlrpc/downloads/list 服务器端可参考此文章,http://www.ibm.com/developerworks/cn/webservices/ws-xml-rpc/

4.WebService,Android本身也不支持基于SOAP的WebService,需要下载相关工具http://code.google.com/p/ksoap2-android/,服务器端支持的应该比较多,如基于.NET可以使用WCF,基于Java的Axis2,Apche CXF等。

5.restful,Android可以使用Http/HttpClient接口,Server使用ASP.NET Web API实现方式。

【使用场景】

跟据两种连接协议的特点来区分,如想做一个即时聊天程序,最好使用Socket,作一个发布类的应用可以使用基于HTTP协议的各种方式,像WordPress使用的XML_PRC.

GMS引起的待机时间短

近日尼日利亚客户反馈,手机在当地纯待机也只有45个小时,我们在实验室测试的待机电流约为10mA,1800mah的电池,理论时间应该在180小时左右,这差距也有点小大了。

从客户反馈的MTK Log中看到:

03-12 15:50:56.351 248 490 D PowerManagerService: acquireWakeLock flags=0x1 tag=DownloadManager

03-12 15:50:56.359 377 17849 V DownloadManager: initiating download for http://www.gstatic.com/android/keyboard/dictionarypack/metadata.json

03-12 15:50:56.359 377 17849 I DownloadManager: Initiating request for download 161369

03-12 15:50:56.359 377 17849 D libc-netbsd: getaddrinfo: www.gstatic.com return error = 0x8 >>

03-12 15:50:56.360 377 17849 D Proxy : prefProxy:DIRECT@

03-12 15:50:56.361 377 17849 W DownloadManager: Aborting request for download 161369: no network connection available

PowerManagerService
一直在持续的获取wakeLock,从Log上看no network connection available,没有网络为什么还在不停的尝试去下载呢。

Google了一下gstatic网站是干吗用的,发现也有人遇到类似的问题,大体上是讲用于获取输入法扩展包的一个地方。想到输入法扩展包,设置当中看到确实有这么一项。但查代码没有发现原生的AndroidInputMethode有此模块。后来突然想到是后来添加了GMS包,里面的LatinImeGoogle覆盖掉了原生的LatinIme,并且多了一个APK“LatinImeDictionaryPack”

删除此DictionaryPack问题得以解决,现在待机能有10~20个小时(还有差距,看来引起功耗大的问题不止一个)。

这应该是GMS包的一个Bug,在stackoverflow有人也问题了,4.0之后的GMS包应该解决了这个问题。

公钥,私钥,SSH Keys,KeyStore,证书

公钥,私钥是一种非对称加密的方式,可以用在很多方面,并且实现的标准不统一。

一,用于远程登陆


例于GithubBitbucket,还有公司的服务器可以使用SSH Keys快捷登陆。


生成方式:
ssh-keygen -t rsa -C “email@email.com”

二,用于给Android上的APK签名(Keystore来签名,Keystore包含公私钥与证书)


使用Eclipse的时候,调试的时候会用到默认的Debug.Keystore.发布的时候会用到Release.Keystore.


生成方式:
keytool.exe -genkey -alias androiddebugkey -keyalg RSA -validity 60000 -keystore debug.keystore

三,用于在编译Android项目的时候,给平台及应用签名


编译的时候会用到四个Key,分别是testkey,platform,shared,media,Android的源码目录 build/target/product/security下面。


生成方式:

development/tools/make_key testkey ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’

development/tools/make_key platform ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’

development/tools/make_key shared ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’

development/tools/make_key media ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’

之前一直有个误区,只需要一个公钥私钥对就可以行遍网络。不同的应用场景,使用公钥,私钥的方式也不一样,如在生成SSHkey的时候,只需要提供一个密码,但在生成Keystore的时候,就需要提供姓名,公司,位置等信息。

前三者之间也不是完全可以转换的,由三转二,有相应的方法,并且从Keystore中可以提取公钥与私钥。

手机定位技术(大话基站LBS,GPS,AGPS,WIFI定位区别)

关于基站,GPS,AGPS,GPS-ONE区别,网上有是一堆文档,这里另一视角来说明:

(Android的CDMA手机,支持GPS,AGPS,使用百度地图)

A.XX新买了一台手机(还没来得急办卡),此时开机,打开百度地图,无法获取位置信息。

1.打开GPS,经过长时间的搜星,定位成功。此为GPS定位。

2.关闭GPS,打开Wifi,连接家里的无线路由,百度地图定位成功。此为WIFI定位

3.若同时打开GPS与Wifi,则先进行Wifi定位,待GPS定好后,使用GPS定位。

B.XX终于办了卡,然后开机,打开百度地图(离线地图,未开2G/3G数据业务,未开GPS,未开Wifi),无法定位。

1.仅打开数据业务,定位成功,此为基站定位

2.又打开GPS,精确定位成功,则为AGPS定位。(网络辅助GPS定位)

总结一下,定位是按最快原则选择的。若同时开启,使用顺序如下,最终还是得靠GPS来准确定位。

WIFI > LSB > AGPS > GPS

参考文档:

科普知识:GPS,AGPS,LBS,wifi,BDS定位介绍和区别