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

下载本文档

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

文档简介

,在android在做ssl开发时,要注意的是android端与服务器端的keystore类型是不一致的:如如下代码:,在androidKeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType());中代码默认拿到的是android的BKS类型.所以需要相应的工具转换:资料如下:AndroidSDK在进行https联机时,对于自签署的凭证是会拒绝联机的,会得到Nottrustedservercertificate的例外。如果使用HttpsURLConnection来联机,网络上可以找到一些破解方法,在此不多谈。使用apachehttpclient其实执行效率比较差一点,但是他最大的好处就是有内建的机制储存cookie,并且也可以跟随server作自动转址。网络上数据比较多的是httpclient3.x版,Android使用httpclient4(而且还有些实作被拿掉)唯一找到比较可信的来源是apachehttpclient官方的example。节录重点段落如下:KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType());FileInputStreaminstream=newFileInputStream(newFile(〃my.keystore"));try(trustStore.load(instream,"nopassword".toCharArray());}finally(instream.close();}8.SSLSocketFactorysocketFactory=newSSLSocketFactory(trustStore);10.Schemesch=newScheme("https",socketFactory,443);11.httpclient.getConnectionManager().getSchemeRegistry().register(sch);KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType());FileInputStreaminstream=newFileInputStream(newFile("my.keystore"));try(trustStore.load(instream,"nopassword".toCharArray());}finally(instream.close();}8.9.SSLSocketFactorysocketFactory=newSSLSocketFactory(trustStore);10.Schemesch=newScheme(〃https〃,socketFactory,443);11.httpclient.getConnectionManager().getSchemeRegistry().register(sch);直接把这段拿去用当然只有一个死字。本来看讨论以为是要制造一个假的空凭证骗过httpclient,从Android文件系统有点微妙开始改来改去,一连串不同的例外或直接crash就不多谈了。解决了档案路径,到底有没有建立等等方面的问题之后才终于发现,假凭证是不行的…所以首先,开启你PC或Mac上的浏览器连上目标网站,从凭证管理的地方把该网站的凭证汇出。每个浏览器做法都不同,请各位发挥正常工程师的水平做完这件事。以Firefox为例,找到site名后选汇出,多半是会得到一个档名为your_site_name.crt的X509(PEM)凭证档。为了之后使用方便,先把这档案复制一份并把档名改为your_site_name.pem。将这个凭证格式从PEM转为BKS格式。这是关键性的一步啊。KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType());KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType());这行中的getDefaultType到底会get到什么type呢?答案:在Android中是BKS。有J2ME经验的人会想说,我看多半是跟J2ME一样的SunJKS格式吧,而且,我不要用getDefaultType就好了,我可以自己指定为PEM,JKS格式啊。是的,你可以。只是你会得到错误讯息说KeyStoreJKSimplementationnotfound。测了半天,看起来Android的httpclient只吃BKS就对了,其他都没实作。那格式要怎么转?根据网络上找到的数据,可以使用KeyToolIUI这个Java工具。打开后从接口选create—KeyStore,格式选BKS,自己命名一下,要不要设密码都可。接着选import—Keystore'sentry—Trustedcertificate一Regularcertificate。Source的部分选PEM并选到刚刚浏览器得到的那个档,Target当然选BKS和刚create出来的档。按OK之后会跳出Entries窗口,下方提示你enternewalias,随便取个名字后ok连打,顺利的话你应该就会有一个your_keystore.bks之类的档案了。要把凭证档放在Androidapp能读到的地方,做法有两种,放在SDcard中,或直接放在resources中。[方案一]放在SDcard的情形:首先仿真器要挂上SDcard,这在Eclipse用AVD工具产生avd时就可以顺便指定SD了。如果习惯用指令的话,也可以用如下指令产生image并mount上:$mksdcard512Mmy_sdcard.so$emulator-sdcard./my_sdcard.so再来要把凭证档copy到SDcard中,目前只知道指令的做法:$adbpushfile_path/your_keystore.bks/sdcard如果有显示类似ftp传输速度之类的讯息应该就是成功了。接着把android程序代码中档案部分改一改viewplaincopytoclipboardprint?FileInputStreaminstream=newFileInputStream(newFile("/sdcard/your_keystore.bks〃));...trustStore.load(instream,null);viewplaincopytoclipboardprint?FileInputStreaminstream=newFileInputStream(newFile("/sdcard/your_keystore.bks〃));...trustStore.load(instream,null);如果没设密码,可以把keystoreload的第二个密码参数改成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);其它同SDcard。还有一个地方要注意,就是SSLport。viewplaincopytoclipboardprint?1.Schemesch=newScheme(〃https〃,socketFactory,443);viewplaincopytoclipboardprint?1.Schemesch=newScheme(〃https〃,socketFactory,443);如果你要连的网站不是用port443,这边请记得改掉。另外如果要使用档案放在resources的做法,getResources()应该只能在Activityclass中执行,如果另外包装联机类别的话请不要直接服用上面的程序代码,要自行从context抓到资源再传过去。在生成SSLkeystore时,注意CN也就是需要填写资料的第一项颁发者或授权者或姓氏这一项,请填写域名或正式IP生成一般命令:1、用JDK的keytool生成密钥storekeytool-genkey-aliasmykey-keystoresrvstore输入密码(程序中密码为‘123456’)和相应的证书信息2、从srvstore中导出证书keytool-export-aliasmykey-filesrvcert.crt-keystoresrvstore输入刚才上面设置的密码3、将证书导到公钥中keytool-import-aliasmytrust-filesrvcert.crt-keystoresrvtrust输入公钥的密码(程序中密码为‘123456’)需要注意的是:一、android3.0以上版本对网络访问控制变得严格了,需要在Activity中加入如下代码才可正常使用httclient或httpurlconnetion连线:StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork()//or.detectAll()foralldetectableproblems.penaltyLog().build());StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());二、android模拟器需要上网时,需要从命令行启动。(如有代理设置)下面是简单的批处理setpath=E:\SDK\android-sdk_r11-windows\toolsemulator@android3.1-http-proxyproxy.cmcc:8080三、在做android开发时进行上网连线时必须在AndroidManifest.xml文件中加入如下代码:<uses-permissionandroid:name="android.permission.INTERNET"/>设置上网访问权限.四、在开发android项目时,注意版本问题。尽量不要以最新的版本开发,会导致应用与手机系统不兼容,在工程中更换版本时可以直接修改:perties文件中的target=android-8和AndroidManifest.xml文件中的<uses-sdkandroid:minSdkVersion="8"/>部分。五、在开发android工程时,需要注意线程的控制,如发送请求或进行流操作时需要涉及到多线程的概念。如果写的代码是单线程的,那么在等待响应时系统UI可能会报出强行关闭或等待等,导致死机现象。所以这时就引入了Handler的概念。具体资料如下:、八、•刖言学习android一段时间了,为了进一步了解android的应用是如何设计开发的,决定详细研究几个开源的android应用。从一些开源应用中吸收点东西,一边进行量的积累,一边探索android的学习研究方向。这里我首先选择了jwood9关键d词^血0「项目。本文将把研究的内容笔记整理,建立一个索引列表。Android.os.Handler涉及较多的知识点,我把一些关键词列举在下面,将主要介绍Handler:android.os.Handler、android.os.Handler.CallbackLooperThreadle、RunnableMessage、Messagequeueandroid.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<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/txt"/><Buttonandroid:id="@+id/btnStartTime"android:text="开始计时"android:layout_width="80dip"android:layout_height="wrap_content"></Button><Buttonandroid:id="@+id/btnStopTime"android:text="停止计时"android:layout_width="80dip"android:layout_height="wrap_content"/><SeekBarandroid:id="@+id/SeekBar01"android:layout_width="match_parent"android:layout_height="wrap_content"></SeekBar></LinearLayout>

这里使用TextView来显示倒计时的时间变化,两个按钮用于控制时间的开始和停止。SeekBar主要是用于查看线程是否被阻塞(阻塞时无法拖动)。日onCreate@OverridepublicvoidonCreate(BundlesavedInstanceState)(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=newHandler(this);btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}在onCreate方法中初始化元素个元素,myHandler=newHandler(this);调用的是Handler(Handler.Callbackcallback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来重写HandleMessage()方法了),因此Activity必须实现android.os.Handler.Callback接口。我们还在将onCreate方法的ThreadId记录在了Log中用以和消息发送、处理时所作的线程进行比较。日I发送消息@OverridepublicvoidonClick(Viewv)(switch(v.getId())(caseR.id.btnStartTime:startTimer();break;caseR.id.btnStopTime:timer.cancel();break;

}privatesynchronizedvoidstartTimer()(timer=newTimer();//TimerTaskupdateTimerValuesTask=newTimerTask()(//©Override//publicvoidrun()(//updateTimerValues();//}////};//自定义的CallBack模式。Task继承自TimerTaskTaskupdateTimerValuesTask=newTask(this);timer.schedule(updateTimerValuesTask,1000,1000);}//执行耗时的倒计时任务。privatevoidupdateTimerValues()(total;Log.d(〃ThreadId〃,"send:"+String.valueOf(Thread.currentThread().getId()));Messagemsg=newMessage();Bundledate=newBundle();//存放数据date.putInt("time”,total);msg.setData(date);msg.what=0;myHandler.sendMessage(msg);//另一种写法//////////////Bundledate=newBundle();//存放数据date.putInt("time”,total);msg.setData(date);

//msg.what=0;//msg.sendToTarget()…epublicvoidTaskRun()(实现Button按钮的事件处理以此进入倒计时操作。这里使用的Timer来执行定时操作(其实我们完全可以另起一个线程)。Task类继承了TimerTask类,里面增加了一个任务处理接口来实现回调模式,应此Activity需要实现该回调的接口ITaskCallBack(这样做是因为我比较不喜欢内部类的编写方法)。日ICallBack接口和Task类publicinterfaceITaskCallBack(voidTaskRun();}publicclassTaskextendsTimerTask(privateITaskCallBackiTask;publicTask(ITaskCallBackiTaskCallBack)(super();iTask=iTaskCallBack;}publicvoidsetCallBack(ITaskCallBackiTaskCallBack)(iTask=iTaskCallBack;

—publicvoidrun()(//TODOAuto-generatedmethodstubiTask.TaskRun();这是Java的回调函数的一般写法。日实现CallBack/***实现消息处理*/@OverridepublicbooleanhandleMessage(Messagemsg)(switch(msg.what)(case0:Bundledate=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;}returnfalse;}可以看到实现android.os.Handler.Callback接口,其实就是对handleMessage()方法进行重写(和内部类的一个区别是,内部类的返回值是Void)。

运行结果TijaetagMessage[板二二ThreadIdcuiCrea.d:109...ThreadIdsend:809...ThreadIdHand1erMessage:109...ThreadIdULsgDate:5909...ThreadIdsend:909...ThreadIdHand1erMessage:109...ThreadIdULsgOaitB:5809...ThreadIdsend:809...ThreadIdHand1erMessage:109...ThreadIdiiLSQDa.te:5709...ThreadIdsend;509...ThreadIdHand1erMessage:103...ThreadIdULEgDate:5609...|-||-|ThreadIdmi】-risend:8Ti-itir■可以看到在onCreate方法中线程的ID是1(UI线程)这与HandlerMessage进行消息处理时是所作的线程ID是一样的,而消息发送的线程ID则为8非UI线程。使用Threadle进行实现日Activity类publicclassThreadHandlerrActivityextendsActivityimplementsCallback,OnClickListener(privateTextViewtxt;privateButtonbtnStart,btnStop;privateHandlermyHandler;privateTimerThreadtimerThread;privateintTotal=30;/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState)(super.onCreate(savedlnstanceState);setContentView(R.layout.main);txt(TextView)findViewByld(R.id.txt);txt(TextView)findViewByld(R.id.txt);btnStart(Button)findViewByld(R.id.btnStartTime);btnStartbtnStop=(Button)findViewByld(R.id.btnStopTime);Log.d("ThreadId","onCread:"+String.valueOf(Thread.currentThread().getId()));myHandler=newHandler(this);btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}/***实现消息处理*/@OverridepublicbooleanhandleMessage(Messagemsg)(switch(msg.what)(case0:Bundledate=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;}returnfalse;}@OverridepublicvoidonClick(Viewv)(switch(v.getId())(caseR.id.btnStartTime://自定义的线程timerThread=newTimerThread(myHandler,60);timerThread.start();break;caseR.id.btnStopTime:timerThread.stop();//timerThread.destroy()}break;日I自定义的线程类*火*自定义的线程类,通过传入的Handler,和Total定期执行耗时操作*@authorlinzijun**/publicclassTimerThreadextendsThread(publicintTotal=60;publicHandlerhandler;/***初始化构造函数@parammhandlerhandler用于发送消息@paramtotal总周期*/publicTimerThread(Handlermhandler,inttotal)(super();handler=mhandler;Total=total;}@Override

publicvoidrun()(while(true)(Total--;if(Total<0)break;try(Thread.sleep(1000);}catch(InterruptedExceptione)(//TODOAuto-generatedcatchblocke.printStackTrace();}Messagemsg=newMessage();Bundledate=newBundle();//存放数据date.putInt("time",Total);msg.setData(date);msg.what=0;Log.d("ThreadId","Thread:"+String.valueOf(Thread.currentThread().getId()));handler.sendMessage(msg);}super.run();}}关于了POST类,也可以直接实现Runnable接口。Post的各种方法是把一个Runnable发送给消息队列,它将在到达时进行处理。日POST

publicclassPostHandlerextendsActivityimplementsOnClickListener,Runnable(privateTextViewtxt;privateButtonbtnStart,btnStop;privateHandlermyHandler;privateTimertimer;privateinttotal=60;@OverrideprotectedvoidonCreate(BundlesavedInstanceState)(//TODOAuto-generatedmethodstubsuper.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=newHandler()(@OverridepublicvoidhandleMessage(Messagemsg)(switch(msg.what)(case0:Bundledate=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;

btnStop.setOnClickListener(this);publicvoidonClick(Viewv)(switch(v.getId())(caseR.id.btnStartTime://myHandler.post(this);myHandler.postDelayed(this,1000);break;caseR.id.btnStopTime:}break;@Overridepublicvoidrun()(while(true)total--;if(total<0)break;try(Thread.sleep(1000);}catch(InterruptedExceptione)(//TODOAuto-generatedcatchblock}…―Messagemsg=newMessage();

Bundledate=newBundle();//存放数据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过去,运行结果是一样的。日代码packagezijunlin.me;importjava.util.Timer;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;importandroid.widget.TextView;publicclassPostHandlerextendsActivityimplementsOnClickListener,Runnable(

privateTextViewtxt;privateButtonbtnStart,btnStop;privateHandlermyHandler;privateTimertimer;privateinttotal=60;privateTimerThreadtimerThread;@OverrideprotectedvoidonCreate(BundlesavedInstanceState)(//TODOAuto-generatedmethodstubsuper.onC

温馨提示

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

评论

0/150

提交评论