在配合android端测试SSL时的笔记.docx_第1页
在配合android端测试SSL时的笔记.docx_第2页
在配合android端测试SSL时的笔记.docx_第3页
在配合android端测试SSL时的笔记.docx_第4页
在配合android端测试SSL时的笔记.docx_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

一、 在做ssl开发时,要注意的是android端与服务器端的keystore类型是不一致的:如如下代码:KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType();,在android中代码默认拿到的是android的BKS类型.所以需要相应的工具转换:资料如下:Android SDK 在进行 https 联机时,对于自签署的凭证是会拒绝联机的,会得到 Not trusted server certificate 的例外。如果使用 HttpsURLConnection 来联机,网络上可以找到一些破解方法,在此不多谈。使用 apache httpclient 其实执行效率比较差一点,但是他最大的好处就是有内建的机制储存cookie,并且也可以跟随 server 作自动转址。网络上数据比较多的是 httpclient 3.x版,Android 使用 httpclient 4 (而且还有些实作被拿掉) 唯一找到比较可信的来源是 apache httpclient 官方的 example。节录重点段落如下:1. KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType();2. FileInputStreaminstream=newFileInputStream(newFile(my.keystore);3. try4. trustStore.load(instream,nopassword.toCharArray();5. finally6. instream.close();7. 8. 9. SSLSocketFactorysocketFactory=newSSLSocketFactory(trustStore);10. Schemesch=newScheme(https,socketFactory,443);11. httpclient.getConnectionManager().getSchemeRegistry().register(sch);1. KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType();2. FileInputStreaminstream=newFileInputStream(newFile(my.keystore);3. try4. trustStore.load(instream,nopassword.toCharArray();5. finally6. instream.close();7. 8. 9. SSLSocketFactorysocketFactory=newSSLSocketFactory(trustStore);10. Schemesch=newScheme(https,socketFactory,443);11. httpclient.getConnectionManager().getSchemeRegistry().register(sch);直接把这段拿去用当然只有一个死字。本来看讨论以为是要制造一个假的空凭证骗过 httpclient,从 Android 文件系统有点微妙开始改来改去,一连串不同的例外或直接crash就不多谈了。解决了档案路径,到底有没有建立等等方面的问题之后才终于发现,假凭证是不 行的 1. 所以首先,开启你PC或Mac上的浏览器连上目标网站,从凭证管理的地方把该网站的凭证汇出。每个浏览器做法都不同,请各位发挥正常工程师的水平做完这件 事。以Firefox为例,找到site名后选汇出,多半是会得到一个档名为 your_site_name.crt 的 X509(PEM) 凭证档。为了之后使用方便,先把这档案复制一份并把档名改为 your_site_name.pem。2. 将这个凭证格式从 PEM 转为 BKS 格式。 这是关键性的一步啊。1. KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType();1. KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType();这行中的 getDefaultType 到底会 get到什么 type 呢?答案:在 Android 中是 BKS。有 J2ME 经验的人会想说,我看多半是跟 J2ME 一样的 Sun JKS 格式吧,而且,我不要用 getDefaultType 就好了,我可以自己指定为 PEM, JKS格式啊。是的,你可以。只是你会得到错误讯息说 KeyStore JKS implementation not found。测了半天,看起来 Android 的 httpclient 只吃 BKS 就对了,其他都没实作。3. 那格式要怎么转?根据网络上找到的数据,可以使用 KeyTool IUI 这个Java工具。打开后从接口选 create KeyStore,格式选 BKS,自己命名一下,要不要设密码都可。接着选 import Keystores entry Trusted certificate Regular certificate。 Source 的部分选 PEM 并选到刚刚浏览器得到的那个档,Target 当然选 BKS 和刚 create 出来的档。按OK之后会跳出Entries窗口,下方提示你enter new alias,随便取个名字后ok连打,顺利的话你应该就会有一个 your_keystore.bks 之类的档案了。4. 要把凭证档放在 Android app 能读到的地方,做法有两种,放在 SD card 中,或直接放在 resources 中。方案一 放在 SD card 的情形:首先仿真器要挂上SD card,这在 Eclipse 用 AVD 工具产生 avd 时就可以顺便指定SD了。如果习惯用指令的话,也可以用如下指令产生 image 并 mount 上:$ mksdcard 512M my_sdcard.so$ emulator -sdcard ./my_sdcard.so再来要把凭证档 copy 到 SD card 中,目前只知道指令的做法:$ adb push file_path/your_keystore.bks /sdcard如果有显示类似 ftp 传输速度之类的讯息应该就是成功了。接着把 android 程序代码中档案部分改一改view plaincopy to clipboardprint?1. FileInputStreaminstream=newFileInputStream(newFile(/sdcard/your_keystore.bks);2. .3. trustStore.load(instream,null);view plaincopy to clipboardprint?1. FileInputStreaminstream=newFileInputStream(newFile(/sdcard/your_keystore.bks);2. .3. trustStore.load(instream,null);如果没设密码,可以把 keystore load 的第二个密码参数改成 null,有设的话当然就把 “nopassword” 改成你的密码。基本上这样应该就大功告成了。方案二 再讲讲凭证放在 resources 的方法。首先把档案复制到项目下的 res/raw/your_keystore.bks 。Eclipse 没有错误的话就 ok,否则多半是你文件名不合规格,稍微改改。接着取用方法是把 android 程序代码改成:1. InputStreaminstream=getResources().openRawResource(R.raw.your_keystore);1. InputStreaminstream=getResources().openRawResource(R.raw.your_keystore);其它同SD card。5. 还有一个地方要注意,就是 SSL port。view plaincopy to clipboardprint?1. Schemesch=newScheme(https,socketFactory,443);view plaincopy to clipboardprint?1. Schemesch=newScheme(https,socketFactory,443);如果你要连的网站不是用 port 443,这边请记得改掉。6. 另外如果要使用档案放在 resources 的做法,getResources() 应该只能在 Activity class 中执行,如果另外包装联机类别的话请不要直接服用上面的程序代码,要自行从 context 抓到资源再传过去。在生成SSL keystore时,注意CN 也就是需要填写资料的第一项 颁发者或授权者或姓氏这一项,请填写域名或正式IP生成一般命令:、用JDK的keytool生成密钥store keytool -genkey -alias mykey -keystore srvstore 输入密码(程序中密码为123456)和相应的证书信息 、从srvstore中导出证书 keytool -export -alias mykey -file srvcert.crt -keystore srvstore 输入刚才上面设置的密码 、将证书导到公钥中 keytool -import -alias mytrust -file srvcert.crt -keystore srvtrust 输入公钥的密码(程序中密码为123456)需要注意的是:一、 android3.0以上版本对网络访问控制变得严格了,需要在Activity中加入如下代码才可正常使用httclient或httpurlconnetion连线: StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() / or .detectAll() for all detectable problems .penaltyLog() .build(); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build(); 二、 android模拟器需要上网时,需要从命令行启动。(如有代理设置)下面是简单的批处理set path=E:SDKandroid-sdk_r11-windowstoolsemulator android3.1 -http-proxy proxy.cmcc:8080三、 在做android开发时进行上网连线时必须在 AndroidManifest.xml 文件中加入如下代码:设置上网访问权限.四、 在开发android项目时,注意版本问题。尽量不要以最新的版本开发,会导致应用与手机系统不兼容,在工程中更换版本时可以直接修改:perties文件中的 target=android-8 和 AndroidManifest.xml 文件中的 部分。五、 在开发android工程时,需要注意线程的控制,如发送请求或进行流操作时需要涉及到多线程的概念。如果写的代码是单线程的,那么在等待响应时系统UI可能会报出强行关闭或等待等,导致死机现象。所以这时就引入了Handler的概念。具体资料如下:前言学习android一段时间了,为了进一步了解android的应用是如何设计开发的,决定详细研究几个开源的android应用。从一些开源应用中吸收点东西,一边进行量的积累,一边探索android的学习研究方向。这里我首先选择了jwood的Standup Timer项目。本文将把研究的内容笔记整理,建立一个索引列表。关键词Android.os.Handler涉及较多的知识点,我把一些关键词列举在下面,将主要介绍Handler: android.os.Handler、android.os.Handler.Callback Looper、 Threadle、Runnable Message、Message queueandroid.os.HandlerHandler在android里负责发送和处理消息。它的主要用途有:1)按计划发送消息或执行某个Runnanble(使用POST方法);2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looperlooper)、Handler(Looperlooper,Handler.Callbackcallback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。倒计时程序利用Timer 编写一个倒计时程序,程序使用Timer和TimerTask来完成倒计时,同时使用sendMessages方法发送消息,然后在HanleMessage里更新UI。Activity布局:Layout 这里使用TextView 来显示倒计时的时间变化,两个按钮用于控制时间的开始和停止。SeekBar主要是用于查看线程是否被阻塞(阻塞时无法拖动)。onCreateOverride public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); txt = (TextView) findViewById(R.id.txt); btnStart = (Button) findViewById(R.id.btnStartTime); btnStop = (Button) findViewById(R.id.btnStopTime); Log.d(ThreadId, onCread: + String.valueOf(Thread.currentThread().getId(); myHandler = new Handler(this); btnStart.setOnClickListener(this); btnStop.setOnClickListener(this); 在onCreate方法中初始化元素个元素,myHandler = new Handler(this); 调用的是 Handler(Handler.Callbackcallback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来 重写HandleMessage()方法了),因此Activity必须实现android.os.Handler.Callback接口。我们还在将onCreate 方法的ThreadId 记录在了Log中用以和消息发送、处理时所作的线程进行比较。发送消息 Override public void onClick(View v) switch (v.getId() case R.id.btnStartTime: startTimer(); break; case R.id.btnStopTime: timer.cancel(); break; private synchronized void startTimer() timer = new Timer(); / TimerTask updateTimerValuesTask = new TimerTask() / Override / public void run() / updateTimerValues(); / / / ; /自定义的CallBack模式。Task继承自TimerTask Task updateTimerValuesTask = new Task(this); timer.schedule(updateTimerValuesTask, 1000, 1000); /执行耗时的倒计时任务。 private void updateTimerValues() total-; Log.d(ThreadId, send: + String.valueOf(Thread.currentThread().getId(); Message msg=new Message(); Bundle date = new Bundle();/ 存放数据 date.putInt(time, total); msg.setData(date); msg.what=0; myHandler.sendMessage(msg); /另一种写法/ Message msg=myHandler.obtainMessage();/ Bundle date = new Bundle();/ 存放数据/ date.putInt(time, total);/ msg.setData(date);/ msg.what=0;/ msg.sendToTarget(); Override public void TaskRun() updateTimerValues(); 实现Button按钮的事件处理以此进入倒计时操作。这里使用的Timer 来执行定时操作(其实我们完全可以另起一个线程)。Task类继承了TimerTask类,里面增加了一个任务处理接口来实现回调模式,应此Activity需要实现该回调的接口ITaskCallBack(这样做是因为我比较不喜欢内部类的编写方法)。ICallBack接口和Task类public interface ITaskCallBack void TaskRun();public class Task extends TimerTask private ITaskCallBack iTask; public Task(ITaskCallBack iTaskCallBack) super(); iTask=iTaskCallBack; public void setCallBack(ITaskCallBack iTaskCallBack) iTask=iTaskCallBack; Override public void run() / TODO Auto-generated method stub iTask.TaskRun(); 这是Java的回调函数的一般写法。实现CallBack /* * 实现消息处理 */ Override public boolean handleMessage(Message msg) switch(msg.what) case 0: Bundle date=msg.getData(); txt.setText(String.valueOf(date.getInt(time); Log.d(ThreadId, HandlerMessage: + String.valueOf(Thread.currentThread().getId(); Log.d(ThreadId, msgDate: + String.valueOf(date.getInt(time); break; return false; 可以看到实现android.os.Handler.Callback接口,其实就是对handleMessage()方法进行重写(和内部类的一个区别是,内部类的返回值是Void)。运行结果可以看到在onCreate 方法中线程的ID是1(UI线程) 这与 HandlerMessage 进行消息处理时是所作的线程ID是一样的,而消息发送的线程ID则为8非UI线程。使用Threadle进行实现Activity类public class ThreadHandlerrActivity extends Activity implements Callback, OnClickListener private TextView txt; private Button btnStart, btnStop; private Handler myHandler; private TimerThread timerThread; private int Total=30; /* Called when the activity is first created. */ Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); txt = (TextView) findViewById(R.id.txt); btnStart = (Button) findViewById(R.id.btnStartTime); btnStop = (Button) findViewById(R.id.btnStopTime); Log.d(ThreadId, onCread: + String.valueOf(Thread.currentThread().getId(); myHandler = new Handler(this); btnStart.setOnClickListener(this); btnStop.setOnClickListener(this); /* * 实现消息处理 */ Override public boolean handleMessage(Message msg) switch(msg.what) case 0: Bundle date=msg.getData(); txt.setText(String.valueOf(date.getInt(time); Log.d(ThreadId, HandlerMessage: + String.valueOf(Thread.currentThread().getId(); Log.d(ThreadId, msgDate: + String.valueOf(date.getInt(time); break; return false; Override public void onClick(View v) switch (v.getId() case R.id.btnStartTime: /自定义的线程 timerThread=new TimerThread(myHandler,60); timerThread.start(); break; case R.id.btnStopTime: timerThread.stop(); /timerThread.destroy(); break; 自定义的线程类* * 自定义的线程类,通过传入的Handler,和Total 定期执行耗时操作 * author linzijun * */public class TimerThread extends Thread public int Total=60; public Handler handler; /* * 初始化构造函数 * param mhandler handler 用于发送消息 * param total 总周期 */ public TimerThread(Handler mhandler,int total) super(); handler=mhandler; Total=total; Override public void run() while(true) Total-; if(Total0) break; try Thread.sleep(1000); catch (InterruptedException e) / TODO Auto-generated catch block e.printStackTrace(); Message msg=new Message(); Bundle date = new Bundle();/ 存放数据 date.putInt(time, Total); msg.setData(date); msg.what=0; Log.d(ThreadId, Thread: + String.valueOf(Thread.currentThread().getId(); handler.sendMessage(msg); super.run(); 这里继承了Thread类,也可以直接实现 Runnable接口。关于POSTPost的各种方法是把一个Runnable发送给消息队列,它将在到达时进行处理。POSTpublic class PostHandler extends Activity implements OnClickListener, Runnable private TextView txt; private Button btnStart, btnStop; private Handler myHandler; private Timer timer; private int total = 60; Override protected void onCreate(Bundle savedInstanceState) / TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); txt = (TextView) findViewById(R.id.txt); btnStart = (Button) findViewById(R.id.btnStartTime); btnStop = (Button) findViewById(R.id.btnStopTime); Log.d(ThreadId, onCread: + String.valueOf(Thread.currentThread().getId(); myHandler = new Handler() Override public void handleMessage(Message msg) switch(msg.what) case 0: Bundle date=msg.getData(); txt.setText(String.valueOf(date.getInt(time); Log.d(ThreadId, HandlerMessage: + String.valueOf(Thread.currentThread().getId(); Log.d(ThreadId, msgDate: + String.valueOf(date.getInt(time); break; ; btnStart.setOnClickListener(this); btnStop.setOnClickListener(this); Override public void onClick(View v) switch (v.getId() case R.id.btnStartTime: /myHandler.post(this); myHandler.postDelayed(this, 1000); break; case R.id.btnStopTime: break; Override public void run() while(true) total-; if(total0) break; try Thread.sleep(1000); catch (InterruptedException e) / TODO Auto-generated catch block e.printStackTrace(); Message msg=new Message(); Bundle date = new Bundle();/ 存放数据 date.putInt(time, total); msg.setData(date); msg.what=0; Log.d(ThreadId, POST: + String.valueOf(Thread.currentThread().getId(); myHandler.sendMessage(msg); Log.d(ThreadId, Thread: + String.valueOf(Thread.currentThread().getId(); 使用POST的方式 是将Runnable 一起发送给处理的线程(这里为UI),如果Runnable的操作比较耗时的话那线程将进入阻塞状态。可以看到先运行 Runnable的Run方法 然后在进入 HandleMessage() 。我还尝试了另一种写法,将TimerThreadPOST过去,运行结果是一样的。代码package zijunlin.me;import java.util.Timer;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.vi

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论