iOSアプリのベストプラクティス

iOSアプリの開発時に、ここで説明しているベストプラクティスを使用すると、iOSデバイスでCitrix Endpoint Managementとモバイルアプリ間の互換性が向上します。

MDXアプリSDKフレームワークおよびラッピング

アプリでMDXアプリSDKフレームワークを使用する場合、ラップを行うには、一致するMDX Toolkitバージョンを使用する必要があります。これらの2つのコンポーネント間でバージョンに不一致がある場合は、操作が失敗する可能性があります。

このような不一致を防ぐために、アプリをISVアプリとしてラップして、アプリモードPremiumまたはGeneralを指定します。これにより、事前にラップされたアプリを提供できるため、顧客がアプリをラップする必要がなくなり、一致しないMDX Toolkitが使用されることがありません。アプリのラップについて詳しくは、MDX Toolkitドキュメントの「Androidモバイルアプリのラッピング」を参照してください。

明示的なアプリIDの使用

使用するiOS Developer EnterpriseアカウントがワイルドカードアプリIDをサポートしていない場合、MDX Toolkitでラップする各アプリに明示的なアプリIDを作成して、各アプリIDにプロビジョニングプロファイルを作成するようにします。

メインスレッドのブロックの回避

メインスレッドでの実行時には、コードブロックは使用しないようにします。これはAppleのガイドラインですが、Citrix Endpoint Managementではさらに重要です。管理対象アプリで一部の操作に時間がかかる場合があり、これらの操作によって以降のスレッド実行がブロックされる場合もあります。ファイル操作、データベース操作、およびネットワーク操作は、発行すると現在実行中のスレッドをブロックする可能性がある操作の例であり、メインスレッドでは避ける必要があります。

強固なコードの作成

特に、アプリの作成時に、『Apple Application Programming Guide』などのAppleのプログラミングガイドに記載されているベストプラクティスに従います。

Appleが公開しているインターフェイスのみ使用します。

アプリを正常にエラーから回復させたり正常に終了させるために、API呼び出しの戻り値を常に確認し、API呼び出しの影響として発生する可能性がある例外を処理します。これはプログラミングの一般的なベストプラクティスに過ぎませんが、管理対象アプリの場合は特に重要です。

基盤となる機能がCitrix Endpoint Managementポリシーによってブロックされていると、正常に動作すると想定されているさまざまなAPIが正しく動作しません。例には、前述したすべての機能が含まれます。

  • 使用できるネットワークがない場合、ネットワークAPIは失敗します。
  • GPSやカメラなどのセンサーAPIは、nullを返すか例外をスローします。

以下のObjective-Cランタイムセレクタは、基盤となる機能がCitrix Endpoint Managementポリシーのためにブロックされている場合は常にnilを返すため、適時処理する必要があります。

オブジェクトクラス セレクタ名
AVCaptureDevice devicesWithMediaType:
MFMailComposeViewController init:
MFMessageComposeViewController initWithNibName:bundle:
NSFileManager URLForUbiquityContainerIdentifier:
NSUbiquitousKeyValueStore defaultStore:
PHPhotoLibrary sharedPhotoLibrary:
UIImagePickerController availableCaptureModesForCameraDevice:
UIPasteboard dataForPasteboardType:
  valueForPasteboardType:
  items:
  dataForPasteboardType:inItemSet:
  valuesForPasteboardType:inItemSet:
UIPopoverController initWithContentViewController:
UINavigationController ctxInitWithRootViewController:
  ctxPopToViewController:animated:

ランタイムインターフェイスのリダイレクト

Citrix Endpoint ManagementではUI Pinプロンプト操作が提供されるため、アプリでこの操作を実行する必要がありません。

Citrix Endpoint Managementの準備が確実に整うように、Citrix Endpoint Managementが複数のオブジェクトクラスセレクタの基盤となるメソッドを開始してアプリのランタイム動作を制御または変更するまで、Objective-Cランタイムセレクタをリダイレクトまたは置換しないことをお勧めします。次の表は、Citrix Endpoint ManagementによってリダイレクトされるObjective-Cクラスセレクタの一覧です。

オブジェクトクラス名 セレクタ名
NSURLProtectionSpace serverTrust
NSURLAuthenticationChallenge sender
NSURLConnection sendSynchronousRequest:returningResponse:error:
  initWithRequest:delegate:startImmediately:
  initWithRequest:delegate:
  connectionWithRequest:delegate:
NSURLConnectionDelegate connection:canAuthenticateAgainstProtectionSpace:
  connection:didReceiveAuthenticationChallenge:
  connection:willSendRequestForAuthenticationChallenge:
NSURLSessionConfiguration defaultSessionConfiguration
  ephemeralSessionConfiguration
ALAssetsLibrary authorizationStatus
AVAudioRecorder record
  prepareToRecord
  recordForDuration:
  recordAtTime:
  recordAtTime:ForDuration:
AVAudioSession recordPermission
AVCaptureDevice デバイス
  devicesWithMediaType:
AVAsset assetWithURL:
AVURLAsset initWithURL:options:
  URLAssetWithURL:options:
AVPlayerItem playerItemWithAsset:
  initWithURL:
  playerItemWithURL:
AVPlayer playerWithPlayerItem:
  initWithPlayerItem:
  initWithURL:
CLLocationManager startUpdatingLocation
UIScrollView setContentOffset:
MFMailComposeViewController canSendMail
  初期化
MFMessageComposeViewController canSendText
  initWithNibName:bundle:
NSFileManager URLForUbiquityContainerIdentifier:
NSUbiquitousKeyValueStore defaultStore
PHPhotoLibrary authorizationStatus
QLPreviewController setDataSource:
  canPreviewItem:
QLPreviewControllerDataSource numberOfPreviewItemsInPreviewController:
  previewController:previewItemAtIndex:
SLComposeViewController isAvailableForServiceType:
UIActivityViewController initWithActivityItems:applicationActivities:
  setExcludedActivityTypes:
UIApplication openURL:
  canOpenURL:
  setApplicationIconBadgeNumber:
UIDocument closeWithCompletionHandler:
  contentsForType:error:
UIDocumentInteractionController interactionControllerWithURL:
  setURL:
  setDelegate:
  presentPreviewAnimated:
  presentOpenInMenuFromBarButtonItem:animated:
  presentOpenInMenuFromRect:inView:animated:
  presentOptionsMenuFromBarButtonItem:animated:
  presentOptionsMenuFromRect:inView:animated:
UIDocumentMenuViewController initWithDocumentTypes:inMode:
UIImage imageNamed:
UIImagePickerController setSourceType:
  takePicture
  startVideoCapture
  isSourceTypeAvailable:
  isCameraDeviceAvailable:
  isFlashAvailableForCameraDevice:
  availableCaptureModesForCameraDevice:
  setMediaTypes
UINavigationController ctxInitWithRootViewController:
  ctxPushViewController:animated:
  ctxPopToViewController:animated:
UIPasteboard generalPasteboard
  pasteboardWithName:create:
  pasteboardWithUniqueName
  setValue:forPasteboardType:
  setData:forPasteboardType:
  setItems:
  addItems:
  dataForPasteboardType:
  valueForPasteboardType:
  numberOfItems
  pasteboardTypes
  pasteboardTypesForItemSet:
  containsPasteboardTypes:
  containsPasteboardTypes:inItemSet:
  アイテム
  itemSetWithPasteboardTypes:
  dataForPasteboardType:inItemSet:
  valuesForPasteboardType:inItemSet:
  string
  strings
  URL
  URL
  image
  images
  color
  colors
UIPopoverController initWithContentViewController
UIPrintInteractionController isPrintingAvailable
  presentAnimated:completionHandler:
  presentFromBarButtonItem:animated:completionHandler:
  presentFromRect:inView:animated:completionHandler:
UIViewController presentViewController:animated:completion:
UIWebView loadRequest:
  setDelegate:
UIWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:
  webViewDidStartLoad:
  webViewDidFinishLoad:
  webView:didFailLoadWithError:
UIWindow makeKeyAndVisible
UIApplicationDelegate applicationDidFinishLaunching:
  application:didFinishLaunchingWithOptions:
  application:willFinishLaunchingWithOptions:
  applicationWillResignActive:
  applicationDidEnterBackground:
  applicationWillEnterBackground:
  applicationDidBecomeActive:
  applicationWillTerminate:
  application:openURL:sourceApplication:annotation:
  application:handleOpenURL:
  applicationProtectedDataWillBecomeUnavailable:
  applicationProtectedDataDidBecomeAvailable:
  application:performFetchWithCompletionHandler:
  application:handleEventsForBackgroundURLSession:completionHandler:
  application:didReceiveLocalNotification:
  application:didReceiveRemoteNotification:
  application:didReceiveRemoteNotification:fetchCompletionHandler:
  application:didRegisterForRemoteNotificationsWithDeviceToken:
  application:didFailToRegisterForRemoteNotificationsWithError:
  applicationSignificantTimeChange:
  application:shouldAllowExtensionPointIdentifier:
QLPreviewController allocWithZone:

データ暗号化機能の確保

MDXの主要機能の1つに、保持されているすべてのデータを透過的に暗号化する機能があります。アプリを変更せずにこの機能を利用でき、実際にこの機能を直接避けることはきません。Citrix Endpoint Management管理者は暗号化を選択的にまたは完全に無効化できますが、アプリではそのようにはできません。

これはMDXの重要な側面の1つであり、以下の点を理解しておく必要があります。

  • 管理対象のプロセスで実行されるすべてのネイティブコードに対して、ファイル暗号化が実行されます。

    ファイルデータ暗号化の実装は、すべてのネイティブコードをサポートしており、AppleフレームワークやApple Objective-Cランタイムを使用するアプリのコードだけではありません。Objective-Cランタイム内にこのランタイムのみを対象として実装されたファイルデータ暗号化を、簡単に無効化できます。

  • 実際に、AVPlayerクラス、UIWebViewクラス、QLPreviewControllerなどの一部のフレームワークAPIは、ユーザーの管理対象アプリプロセスとは異なる実行コンテキストでiOSサービスプロセスによって実装されます。

    これらのサービスプロセスはMDX暗号化ファイルデータを暗号化解除できないため、管理対象アプリでは、暗号化解除された一時的なデータコピー(管理対象アプリにより5秒後に削除)をサービスプロセスに提供する必要があります。これらの特定のクラスはApple実装であるため、これらのクラスに対して提供されるデータの抑制制御が失われるので、これらのクラスを使用する場合の制限を理解しておくことが重要です。

  • メモリマッピングではアプリ呼び出しファイルI/Oシステムコールインターフェイスが使用されるため、 Citrix Endpoint Management暗号化に問題が発生します。

    ファイルがメモリマップされると、そのファイルのI/O要求は、Citrix Endpoint Managementをバイパスし、ユーザーアプリのコンテキストの外部で管理されます。管理対象アプリによるすべてのPOSIX mmap(2)呼び出しがMAP_PRIVATEおよびMAP_ANONとしてマップされ、ファイル説明には関連付けられません。オペレーティングシステムによる後続のデータページイン以降にすべてのデータでファイル説明が[fault]に指定されている場合、mmap呼び出し中にすべてのマップデータで読み取りが試みられると、Citrix Endpoint Managementによって暗号化解除されずに暗号化データが読み取られます。アプリ内でメモリページの解放が行われず、メモリマップされるデータの量が小さいため、この手法はCitrix Endpoint Managementでテストされたすべてのアプリで成功しています。

  • 暗号化によって、オーバーヘッドが大幅に増加します。パフォーマンスの低下を防ぐために、開発者はディスクI/Oを最適化する必要があります。たとえば、同じ情報の読み取りおよび書き込みを繰り返し行う場合は、アプリケーションレベルキャッシュを実装します。

  • Citrix Endpoint Managementは、Apple libsqlite.dylibのインスタンスのみを暗号化します。アプリケーションがlibsqlite.dylibのプライベートバージョンと直接リンクしたりそこに埋め込まれたりすると、そのプライベートライブラリのデータベースインスタンスはCitrix Endpoint Managementによって暗号化されません。

  • Apple SQLiteデータベースは、SQLite仮想ファイルシステムレイヤーを使用してCitrix Endpoint Managementによって暗号化されます。

    パフォーマンスが問題になる場合があります。標準のデータベースキャッシュサイズは2000ページまたは8メガバイトです。データベースのサイズが大きい場合、開発者はデータベースキャッシュサイズを増やすようにSQLiteプラグマを指定することが必要になる可能性があります。Objective-C Core Dataフレームワークで、Persistent StoreオブジェクトをPersistent Store Controllerオブジェクトに追加するときに、SQLiteプラグマをオプションディレクトリとして追加できます。

  • ライブラリがファイルI/Oインターフェイスに再リンクされて内部的にメモリマッピングが広範に使用されるため、SQLite WALモードはサポートされていません。

  • NSURLCache DiskCacheが、SQLiteデータベースを使用してiOSによって実装されます。このデータベースは管理対象外のiOSサービスプロセスによって参照されるため、関連付けられたディスクキャッシュがCitrix Endpoint Managementによって無効化されます。

  • 次の表は、ハードコードされて除外されるファイルパス名のパターンです。

       
    .plist プロセスのコンテキストの外側でのiOSシステムプロセスによるアクセスのため、除外されます。
    .app アプリケーションバンドル名のレガシな部分文字列。明示的なアプリケーションバンドルパスが除外されるようになったので、この部分文字列は廃止される予定です。
    .db ファイルがSQLiteデータベースでない場合、このサフィックスが付いたファイルは暗号化されません。
    /System/Library アプリバンドルサンドボックスディレクトリ内に存在するファイルパスおよびアプリデータサンドボックス外のファイルパスは暗号化できません。iOSでは、インストールされたアプリは読み取り専用であり、実行時にアプリによって生成されて保存されるアプリデータファイルとは別のディレクトリに保存されます。
    Library/Preferences ファイルはiOSから直接アクセスされます。通常、このディレクトリパスには.plistファイルのみ存在します。
    /com.apple.opengl/ ファイルはiOSから直接アクセスされます。
    csdk.db レガシなCitrix SSLSDK SQLiteデータベース
    /Library/csdk.sql Citrix SSLSDK SQLiteデータベース
    CtxLog_ Citrixログファイル名のプレフィックス
    CitrixMAM.config MDX内部ファイル名
    CitrixMAM.traceLog レガシなMDX内部ファイル名
    CtxMAM.log MDX内部ファイル名
    data.999 MDX内部ファイル名
    CTXWrapperPersistentData MDX内部ファイル名
    /Documents/CitrixLogs MDXログディレクトリ
    /Document/CitrixLogs.zip 圧縮されたMDXログのディレクトリ名
    アプリバンドルディレクトリパスのファイル アプリファイルの読み取り専用ディレクトリ
  • Citrix Endpoint Managementにより、実行時にApple Objective-C QLPreviewControllerオブジェクトクラスのインスタンスがプライベートのCitrix Endpoint Management SecureViewControllerクラスのインスタンスに置換されます。Citrix Endpoint Management SecureViewControllerクラスは、Apple Objective-C UIWebViewオブジェクトクラスから派生されます。QLPreviewControllerオブジェクトクラスは、オーディオやpdfタイプなど、UIWebViewオブジェクトクラスではネイティブにはサポートされていないいくつかのファイル形式をネイティブにサポートしています。

  • 最適なパフォーマンスを得るには、4096バイトの倍数であるファイルオフセットに対してファイルI/O要求が発行される必要があります。また、4096バイトの倍数である長さに対して発行される必要があります。

  • Citrix Endpoint Management暗号化では、O_NONBLOCKファイルモードフラグはサポートされていません。このファイルモードフラグは、Citrix Endpoint Managementによる処理時にモードリストから削除されます。

暗号化のユーザーエントロピー

Citrix Endpoint Managementの特定の暗号化オプションでは、暗号キーを生成するにはエンドユーザーがPINを入力する必要があります。このオプションはユーザーエントロピーと呼ばれるもので、アプリケーションで特定の問題が発生する可能性があります。

特に、ユーザーがPINを入力するまでファイルアクセスまたはデータベースアクセスは実行できません。PIN UIが表示できるようになる前に実行されるI/O操作が場所に存在する場合、このI/O操作は常に失敗します。

アプリケーションにこの問題がないことを確認するには、ユーザーエントロピーが有効になった状態でテストします。Citrix Endpoint ManagementクライアントプロパティEncrypt secrets using Passcodeによって、ユーザーエントロピーを追加します。このクライアントプロパティはデフォルトでは無効になっており、Citrix Endpoint Managementコンソールを使用して [構成]>[設定]>[詳細]>[クライアントプロパティ] で構成します。

データ抑制機能

  • リモートビューコントローラーはMDX管理対象アプリとは別のプロセスコンテキストで実行されるので、リモートビューコントローラーではセキュリティ抑制(データ暗号化、ポリシーブロックのコピー、切り取り、貼り付けなど)が行われません。
  • UIResponderではコピー操作のみがサポートされます。切り取りや削除などの他の操作は、サポートされていません。
  • Airdropは、UIレベルでのみインターセプトされ、それよりも低いレベルではインターセプトされません。
  • MFIおよびBluetoothはインターセプトされません。

アイコンファイルのサポート

MDXのラップには、ホーム画面アイコンまたはアプリアイコンとして使用できる1つ以上のアイコンが必要です。アプリ開発者は、アセットカタログにアイコンを追加するか、またはInfo.plistのCFBundleIconsキーまたはCFBundleIconFilesキーを使用できます。

MDX Toolkitでは、Info.plist内の既知のplistの場所一覧から一番目のキーが取得されます。

  • CFBundleIcons
  • CFBundlePrimaryIcon
  • CFBundleIconFiles
  • UINewsstandIcon
  • CFBundleDocumentTypes

これらのキーがInfo.plist内に見つからない場合、MDX Toolkitでアプリバンドルのルートフォルダ内にある以下のアイコンのいずれかが特定されます。

  • Icon.png
  • Icon-60@2x.png
  • Icon-72.png
  • Icon-76.png

ネットワークおよびMicro VPN

MDXでは現在、アプリによって直接発行されたネットワーク呼び出しのみ管理されています。一部のDNSクエリはAppleフレームワークによって直接発行されるため、MDXでは管理されません。

ネットワーク用のさまざまなCitrix Endpoint Managementポリシーオプションが管理者に提供されています。ネットワークアクセスポリシーは、アプリのネットワークアクティビティを次のように禁止、許可、リダイレクトします。

  • デフォルトでは、ネットワークはアプリに対して完全にブロックされます。ネットワークアクセスポリシーが[ブロック]に設定されている場合、アプリによって使用されるネットワークAPIは失敗します。前述のガイドラインに基づいて、このような失敗を正常に処理する必要があります。
  • ネットワークアクセスポリシーが[制限なし]に設定されている場合、ネットワーク呼び出しはすべて直接転送され、トンネル処理されません。
  • ネットワークアクセスポリシーが[内部ネットワークへトンネル]に設定されている場合、ネットワーク呼び出しはすべてNetScaler Gateway経由でトンネル処理されます。このポリシーによるトンネル処理は、優先VPNモードポリシーによって制御されます。

優先VPNモードポリシーでは、内部ネットワークへトンネルする接続に対して初期モードを設定します。

  • 優先VPNモードポリシーが[セキュアブラウズ]に設定されている場合、http/https URLが書き込まれます。セキュアブラウズでは、httpトラフィックおよびhttpsトラフィックのみトンネル処理できます。セキュアブラウズの大きなメリットは、httpトラフィックとhttpsトラフィックのシングルサインオン(SSO)、およびPKINIT認証です。Androidでは、セキュアブラウズはセットアップのオーバーヘッドが小さいため、Web閲覧タイプの操作に対する推奨オプションとなっています。
  • 優先VPNモードポリシーが[完全VPNトンネル]に設定されている場合、管理対象アプリケーションからのトラフィックはすべてNetScaler Gatewayを介してトンネル処理されます。

制限事項:

  • WkWebViewはサポートされていません。
  • ユーザーは内部WebサイトにホストされているビデオをiOSラップされたMDXアプリで再生できません。MDXによってインターセプトされないデバイス上で、メディアプレーヤープロセスでビデオが再生されるためです。
  • NSURLSessionのバックグラウンドダウンロード(NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier)はサポートされていません。
  • ネットワークアクセスポリシーが[ブロック]に設定されている場合、UDPトラフィックがブロックされます。ネットワークアクセスポリシーが[内部ネットワークへトンネル]に設定されている場合、UDPトラフィックはトンネル処理されません。
  • MDXラップされたアプリでは、受信接続をリスンするソケットサーバーを置換できません。ただし、MDXでラップされたアプリでは、クライアントソケットを使用してサーバーに接続できます。

サードパーティ製ライブラリのサポート

一部のアプリケーションフレームワークは、Citrix Endpoint Managementで互換性の問題があります。

  • Xamarinクロスプラットフォーム開発環境で開発されたアプリはサポートされています。使用例とテスト例が不十分なため、他のクロスプラットフォーム開発環境でのサポートは正式に表明されていません。
  • SQLCipherではメモリマッピングを使用するため、暗号化が機能しません。解決策として、SQLCipherを使用しないという方法があります。また、暗号化除外ポリシーを使用してデータベースファイルを暗号化から除外するという方法もあります。Citrix Endpoint Management管理者は、Citrix Endpoint Managementコンソールでポリシーを構成する必要があります。
  • OpenSSL libcrypto.aライブラリおよびlibssl.aライブラリに直接リンクしているアプリおよびサードパーティライブラリでは、シンボルの欠落が原因のリンクエラー、および複数シンボル定義が原因のリンクエラーが発生する可能性があります。
  • Appleプッシュ通知サービスのサポートが必要なアプリでは、Appleで必要とされている特定の手順に従う必要があります。
  • Citrix Endpoint Managementでは、SQLiteデータベース内でログ先行書き込み(WAL)ファイルおよびメモリマップファイルのサポートを無効化するために、SQLiteデータベースバージョンが1に明示的に設定されます。SQLiteバージョン2またはバージョン3でSQLiteインターフェイスに直接アクセスしようとすると、そのアクセスは失敗します。