2013年12月16日月曜日

独自のSSL証明書で、HTTPS通信をしたい

次のような証明書を受け付けるクラス例です。

-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIJAPMefpUKXulbMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV
...
vHfWjlx0hIVJ7YHycQXny1Io5fQovDSfh6qR1aUTRf6Bg7Ym
-----END CERTIFICATE-----

クラス:
// http://d.hatena.ne.jp/Kazzz/20110320/p1
public class MyHttpClient extends DefaultHttpClient {
 ByteArrayInputStream si;

 public MyHttpClient(String x509) {
  try {
   si = new ByteArrayInputStream(x509.getBytes("UTF-8"));
  } catch (UnsupportedEncodingException e) {
   throw new RuntimeException(e);
  }
 }

 @Override
 protected ClientConnectionManager createClientConnectionManager() {
  SchemeRegistry registry = new SchemeRegistry();
  registry.register(new Scheme("http", PlainSocketFactory
    .getSocketFactory(), 80));
  registry.register(new Scheme("https",
    (SocketFactory) createSSLSocketFactory(), 443));
  return new SingleClientConnManager(getParams(), registry);
 }

 private SSLSocketFactory createSSLSocketFactory() {
  KeyStore keyStore;
  try {
   si.reset();
   CertificateFactory cf = CertificateFactory.getInstance("X.509");
   Certificate oreore = cf.generateCertificate(si);
   keyStore = KeyStore.getInstance("BKS");
   keyStore.load(null, null);
   keyStore.setCertificateEntry("alias", oreore);
   SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore);
   socketFactory
     .setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
   return socketFactory;
  } catch (KeyStoreException e) {
   return null;
  } catch (NoSuchAlgorithmException e) {
   return null;
  } catch (CertificateException e) {
   return null;
  } catch (UnsupportedEncodingException e) {
   return null;
  } catch (IOException e) {
   return null;
  } catch (KeyManagementException e) {
   return null;
  } catch (UnrecoverableKeyException e) {
   return null;
  }
 }
}
使い方:
  return new MyHttpClient(x509);

x509には証明書の文字列を設定してください。

API level 9 準拠

他のアプリでファイルを開きたい

AndroidManifest.xmlを編集

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="jp.digitaldolphins.mydd.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true" >
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

android.support.v4.content.FileProviderを宣言します。

res/xml/file_paths.xmlを作成

<paths xmlns:android="http://schemas.android.com/apk/res/android" >

    <files-path
        name="my_files"
        path="my_files/" />

</paths>

一時ファイルを作成

 File dir = new File(MobileSearchActivity.this.getFilesDir(),
   "my_files");
 dir.mkdir();
 File fp2 = new File(dir, title);
 FileOutputStream os = new FileOutputStream(fp2);
フォルダ階層有りのファイルを作るときは、FileOutputStreamで良いようです。Context.openFileOutputを使うことばかり考えていましたが、そうではないみたいです。

インテントを作動させて、他のアプリを開く

 Uri uriForFile = FileProvider.getUriForFile(
   MobileSearchActivity.this,
   "jp.digitaldolphins.mydd.fileprovider", fp2);
 Intent nIntent = new Intent(Intent.ACTION_VIEW);
 nIntent.setDataAndType(uriForFile, mime);
 nIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
   | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
 List<ResolveInfo> resInfoList = getPackageManager()
   .queryIntentActivities(nIntent,
     PackageManager.MATCH_DEFAULT_ONLY);
 for (ResolveInfo resolveInfo : resInfoList) {
  grantUriPermission(resolveInfo.activityInfo.packageName,
    uriForFile, Intent.FLAG_GRANT_READ_URI_PERMISSION);

 }
 MobileSearchActivity.this.startActivity(nIntent);

jp.digitaldolphins.mydd.fileproviderfp2mimeMobileSearchActivity.thisなどは、自分の物で書き換えます。後はコピペで行けると思います。

繰り返しが入っているのは、他のアプリへのアクセスを許可する為のコードです。

API level 9 準拠