Androidアプリのベストプラクティス
ここで説明しているベストプラクティスを使用すると、AndroidデバイスでCitrix Endpoint Managementとモバイルアプリ間の互換性が向上します。
MDXアプリSDKおよびラッピング
アプリケーションでMDXアプリSDKを使用する場合、ラップを行うには、一致するMDX Toolkitバージョンを使用する必要があります。これらの2つのコンポーネント間でバージョンに不一致がある場合は、操作が失敗する可能性があります。
このような不一致を防ぐために、アプリケーションの種類PremiumまたはGeneralでアプリケーションをラップします。これにより、事前にラップされたアプリを提供できるため、顧客がアプリをラップする必要がなくなり、一致しないMDX Toolkitが使用されることがありません。アプリのラップについて詳しくは、「Androidモバイルアプリのラッピング」を参照してください。
メインスレッドのブロックの回避
メインスレッドでの実行時には、コードブロックは使用しないようにします。これはGoogleのガイドラインですが、Citrix Endpoint Managementではさらに重要です。管理対象アプリで一部の操作に時間がかかる場合があり、これらの操作によって以降のスレッド実行がブロックされる場合もあります。
以下はコードブロックの一例です。
- ファイル操作またはデータベース操作
- ネットワーク操作
端的に言えば、onCreateなどのアプリケーションライフサイクルメソッドはすべて、メインスレッドで実行されます。
Googleから提供されているStrictMode APIを使用すると、コードブロックを検出するのに役立ちます。詳しくは、このブログ投稿を参照してください。https://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html
強固なコードの作成
特に、戻り値を確認するか、またはフレームワークAPIの例外をキャッチする必要があります。これはプログラミングの一般的なベストプラクティスに過ぎませんが、管理対象アプリケーションの場合は特に重要です。
基盤となる機能がCitrix Endpoint Managementポリシーによってブロックされていると、正常に動作すると想定されているさまざまなAPIが正しく動作しません。例には、前述したすべての機能が含まれます。
- 使用できるネットワークがない場合、ネットワークAPIは失敗します。
- GPSやカメラなどのセンサーAPIは、nullを返すか例外をスローします。
- 管理対象外のアプリケーションに対するインテントは失敗します。
- メインスレッドから使用されている場合、ファイルアクセスおよびデータベースアクセスは失敗する可能性があります。詳しくは、この記事後半の「データ暗号化機能の確保」および「暗号化のユーザーエントロピー」を参照してください。
失敗が発生した場合、アプリケーションによって問題が正常に処理され、アプリケーションはクラッシュしません。
フックの制限
MDXは、APKのDEXコードを変更することで、バイナリのAndroidアプリケーションに機能を追加します。いくつか制限があります。
- Citrix Endpoint Managementでは、4.0より前のAndroid SDKバージョンで提供されていた、廃止になったフレームワーククラスは管理されない場合があります。これらの廃止になったクラスは避ける必要があります。
- ほとんどの機能がJava/AndroidフレームワークAPIに追加されます。通常、ネイティブ(C/C++)コードは管理されません。ただし、ネイティブコードの場合でも、例外としてファイル暗号化は引き続き実行されます。
- JNIを使用してJava機能にアクセスするネイティブコードでは、ユ-ザーアプリケーションのコードのみを対象とする必要があります。つまり、JNIを使用してJavaまたはAndroidフレームワークメソッドを呼び出さないでください。代わりに、プロキシ設計パターンを使用し、必要なフレームワーククラスをJavaクラスに「ラップ」します。その後、ネイティブコードからクラスを呼び出します。
データ暗号化機能の確保
MDXの主要機能の1つに、保持されているすべてのデータを透過的に暗号化する機能があります。アプリを変更せずにこの機能を利用でき、実際にこの機能を直接避けることはきません。管理者は暗号化を選択的にまたは完全に無効化できますが、アプリケーションではそのようにはできません。
これはMDXの重要な側面の1つであり、以下の点を理解しておく必要があります。
-
管理対象のプロセスで実行されるすべてのJavaコードおよびネイティブコードに対して、ファイル暗号化が実行されます。
-
メディアプレーヤーや印刷サポートなどの一部のフレームワークAPIは、実際には別のOSプロセスで実行されます。このようなAPIを使用する場合、問題が発生することがあります。
- 例:アプリケーションがファイルをディスク(暗号化適用)に保存して、ファイルへの参照をメディアAPIに渡します。メディアAPIはファイルを読み取ろうとしますが、暗号化されたコンテンツを理解しません。メディアAPIが失敗し、アプリケーションがクラッシュする場合もあります。
- 例:ファイルハンドル(暗号化されたファイルを開始)を作成して、カメラAPIに割り当てます。カメラプロセスが、暗号化されたファイルに暗号化されていないデータを直接書き込みます。アプリケーションがそのデータを読み取ろうとすると、データの暗号化が解除されてガベージが生成されます。
-
個別のプロセスを処理する方法として、関連するAPIにファイルを渡す前に、ファイルの暗号化を解除するという方法があります。または、APIによってデータが書き込まれる場合は、まずAPIによってデータを書き込ませて、APIが終了したらデータを暗号化するという方法もあります。いくつか手順を実行する必要があります。
- 暗号化されないままで残す領域を指定します。顧客向けにこれを文書化する必要があります。Citrix Endpoint Management管理者が暗号化例外ポリシーを作成する必要があるためです。
- 暗号化を解除するには、標準の(暗号化された)場所から暗号化解除された場所にファイルをコピーするだけです。ファイル移動処理ではなく、バイトコピーを実行する必要があることに注意してください。
- 暗号化するには、方向を逆にします。暗号化解除された場所から、暗号化された場所にコピーします。
- 暗号化解除されたファイルは、不要になったら削除します。
-
暗号化されたファイルのメモリマッピングはサポートされていません。メモリマッピングを実行するAPIを呼び出した場合、そのAPIは失敗し、エラーを処理する必要があります。メモリマッピングの直接的および間接的な使用は、可能な限り回避してください。間接的な使用のおもなケースとして、サードパーティのSqlCipherライブラリがあります。
メモリマッピングを回避できない場合は、関連ファイルを除外する暗号化除外ポリシーを管理者が指定する必要があります。顧客向けに、これを文書化する必要があります。
-
暗号化によって、オーバーヘッドが大幅に増加します。パフォーマンスの低下を防ぐために、ファイルI/Oを最適化するようにします。たとえば、同じ情報の読み取りおよび書き込みを繰り返し行う場合は、アプリケーションレベルキャッシュを実装します。
-
データベースは単なるファイルであるため、データベースも暗号化されます。パフォーマンスがここでも問題になる場合があります。標準のデータベースキャッシュサイズは2000ページまたは8メガバイトです。データベースのサイズが大きい場合は、このキャッシュサイズを増やすことができます。
メモリマッピングの制限により、SQLite WALモードはサポートされていません。
暗号化のユーザーエントロピー
Citrix Endpoint Managementの特定の暗号化オプションでは、暗号キーを生成するにはエンドユーザーがPINを入力する必要があります。このオプションはユーザーエントロピーと呼ばれるもので、アプリケーションで特定の問題が発生する可能性があります。
特に、ユーザーがPINを入力するまでファイルアクセスまたはデータベースアクセスは実行できません。PIN UIが表示できるようになる前に実行されるI/O操作が場所に存在する場合、このI/O操作は常に失敗します。影響がいくつかあります。
- メインスレッドでファイル操作およびデータベース操作が実行されないようにします。たとえば、アプリケーションオブジェクトのonCreate()メソッドでファイルを読み取ろうとすると、その読み取りは常に失敗します。
- サービスやコンテンツプロバイダーなどのバックグラウンド操作は、アプリケーションアクティビティがない場合でも実行される場合があります。これらのバックグラウンドコンポーネントはPIN UIを表示できないため、ファイルアクセスまたはデータベースアクセスを実行できません。アプリケーションでアクティビティが実行されると、バックグラウンド操作でI/O操作を実行できるようになります。
ユーザーエントロピーのために暗号キーが使用できない場合、次のような失敗メカニズムがあります。
- PINが使用可能になる前にメインスレッドがデータベースにアクセスした場合、アプリケーションは強制終了されます。
- PINが使用可能になる前にメインスレッド以外のスレッドがデータベースにアクセスした場合、PINが入力されるまでそのスレッドはロックされます。
- PINが使用可能になる前にデータベース以外へのアクセスが開始された場合、オープン操作は失敗します。Cレベルでは、EACCESエラーが返されます。Javaでは、例外がスローされます。
アプリケーションにこの問題がないことを確認するには、ユーザーエントロピーが有効になった状態でテストします。Citrix Endpoint ManagementクライアントプロパティEncrypt secrets using Passcodeによって、ユーザーエントロピーを追加します。このクライアントプロパティはデフォルトでは無効になっており、Citrix Endpoint Managementコンソールを使用して [構成]>[設定]>[詳細]>[クライアントプロパティ] で構成します。
ネットワークおよびMicro VPN
ネットワーク用のさまざまなCitrix Endpoint Managementポリシーオプションが管理者に提供されています。ネットワークアクセスポリシーは、アプリのネットワークアクティビティを禁止、許可、リダイレクトします。
重要:
MDX Toolkitバージョン18.12.0リリースには、以前のポリシーを組み合わせたり置き換えたりした新しいポリシーが含まれています。 [ネットワークアクセス]ポリシーは[ネットワークアクセス]、[優先VPNモード]、[VPNモードの切り替えを許可]を組み合わせたものです。[除外の一覧]ポリシーは、[分割トンネルの除外対象一覧]に置き換えられます。[オンラインセッションを必須とする]ポリシーは、[Micro VPNセッションを必須とする]ポリシーに置き換えられます。詳しくは、「以前のリリースの新機能」を参照してください。
使用できるオプションは、次のとおりです。
- 以前の設定を使用:デフォルトでは、過去のポリシーで設定済みの値が使用されます。値の変更後は、[以前の設定を使用] に戻さないでください。また、新しいポリシーに対する変更は、ユーザーがアプリをバージョン18.12.0以降にアップグレードするまで反映されません。
- 禁止:アプリが使用するネットワークAPIは機能しません。前述のガイドラインに基づいて、このような失敗を正常に処理する必要があります。
- 制限なし:ネットワーク呼び出しはすべて直接転送され、トンネリングされません。
- トンネル-完全VPN:管理対象アプリケーションからのトラフィックはすべてCitrix Gatewayを介してトンネリングされます。
制限事項:Citrix Endpoint Managementはソケットサーバーをサポートしていません。ラッピングされたアプリ内でソケットサーバーを実行している場合、ソケットサーバーへのネットワークトラフィックはCitrix Gatewayを介してトンネリングされません。
モバイルアプリケーション開発フレームワークのサポート
一部のアプリケーションフレームワークは、Citrix Endpoint Managementで互換性の問題があります:
- PhoneGapでは、位置情報サービスがブロックされません。
- SQLCipherではメモリマッピングを使用するため、暗号化が機能しません。解決策として、SQLCipherを使用しないという方法があります。また、暗号化除外ポリシーを使用してデータベースファイルを暗号化から除外するという方法もあります。Citrix Endpoint Management管理者は、Citrix Endpoint Managementコンソールでポリシーを構成する必要があります。
デバッグに関するヒント
ラップされたアプリケーションをデバッグする場合、以下のヒントを考慮します。
- ラップされていないバージョンのアプリケーションで問題が発生するかどうかを判断します。ラップされていないバージョンで問題が発生する場合は、通常のデバッグ方法を使用します。
- さまざまなCitrix Endpoint Managementポリシーを無効にしてみてください。
- こうすると、互換性のない箇所を特定するのに役立ちます。ポリシーを無効化すると、関連する制限がMDXによって適用されなくなるため、アプリケーションがラップされていないかのようにこれらの機能をテストできます。
- ポリシーを無効化すると問題が解決された場合、関連するAPIのエラーがアプリケーションでチェックされないことが問題である可能性があります。
- 未変更であるが再署名されたアプリケーションが動作しない場合は、次の手順を実行します。
-
JARを使用してAPKのコンテンツを解凍します。
jar xvf {some.apk}
-
META-INFフォルダーを削除します。
rm -rf META-INF
-
JARを使用して新しいAPKにコンテンツを再圧縮します。
jar cvf {/tmp/new.apk} *
-
JARSIGNERを使用して新しいAPKに署名します。
jarsigner -keystore {some.keystore} -storepass {keystorepassword} -keypass {keypassword} {/tmp/new.apk} {keyalias}
-
アプリケーションが引き続き動作しない場合は、使用した元のAPKとは異なる署名証明書を使用してアプリケーションをラップすることはできません。
-
- 逆コンパイルまたは再コンパイルされたapkが動作しない場合は、次の手順を実行します。
-
APKTOOLを使用して逆コンパイルおよび再コンパイルします。
apktool d {some.apk} -o {some.directory}
apktool b {some.directory} -o {new.apk}
-
上記の説明に従って、JARSIGNERを使用してAPKに署名します。
-
アプリケーションが引き続き動作しない場合は、サードパーティのAPKTOOLのバグです。
-
- アプリケーションのラップが動作しない場合は、次の手順を実行します。
- APKTOOLフレームワークを削除して再度ラップしてみます。
- Mac/Linux: rm -rf ~/Library/apktool/framework
- Windows: del /q /s C:\Users\{username}\apktool\framework
- ラッパーによって使用されているAPKTOOLと、前の手順で正常に逆コンパイルおよび再コンパイルしたときに使用したAPKTOOLを比較します。
- 同じAPKTOOLバージョンである場合、ラッパーにバグがあります。
- 異なるAPKTOOLバージョンである場合、MDX Toolkitユーティリティに統合されているAPKTOOLにバグがある可能性があります。
- ManagedAppUtility.jarのコンテンツを解凍します。
- 前の手順でアプリケーションを正常にラップしたときに使用したAPKTOOL.jarのコンテンツで、上書きします。
- 新しいManagedAppUtility.jarにコンテンツを再圧縮します。
- アプリケーションをラップして、組み込みのAPKTOOLのバグを確認します。
- APKTOOLフレームワークを削除して再度ラップしてみます。
- ラップされているアプリケーションを実行してログ情報を取得します。
-
grepを使用し、アプリケーションに何が発生しているのかを調べます。
アプリケーションのアクティビティを追跡するには:grep “MDX-Activity”
アプリケーションのMDXロックを追跡するには:grep “MDX-Locked”
両方のログを同時に表示するには:egrep “MDX-Act MDX-Loc” -
アプリケーション非応答エラーが表示される場合は、ADBを使用してANRトレースをプルします。
-
- [このアプリケーションで開く]を使用するときなど、複数のアプリケーションを操作するときに問題が発生する場合は、次の手順を実行します。
- 暗号化ポリシーとセキュリティグループ設定が各アプリケーション間で同じであることを確認します。
- 別のアプリケーションを試します。テストしているいずれかのアプリケーションのバグである場合があります。
- 関連するすべてのアプリケーションのログを取得します。Secure Hubによって、ログを処理して個々のアプリケーションのログを電子メール送信できます。[マイアプリ]画面で、右にスワイプして[サポート]画面を表示します。次に、画面下部にある[ヘルプ]ボタンをクリックします。
前述のツール以外に、以下のツールも役立ちます。
-
AAPTを使用してアプリケーションに関する情報をダンプします。
aapt dump badging {some.apk}
-
DUMPSYSコマンドをデバイスで実行します。
adb shell dumpsys 2>&1 | tee {dumpsys.out}
-
DEX2JARを使用してpseudo-Javaにクラスを再コンパイルします。
dex2jar {some.apk}
Dual-Dexラップアプリケーションからクラスを変換します。
apktool d {some.apk} -o {some.dir}
dex2jar {some.dir}/assets/secondary-1.dex
-
JD-GUIを使用してpseudo-Javaコードを表示します。
-
BAKSMALIを使用してDual-Dexラップアプリケーションからアプリケーションクラスを逆コンパイルします。
-
ラップされたAPKを逆コンパイルするには:
apktool d {some.apk} -o {some.dir}
-
上記の呼び出しで逆コンパイルされないアプリケーションのクラスを逆コンパイルするには:
baksmali {some.dir}/assets/secondary-1.dex -o {some.dir}/smali
-