iOSアプリのベストプラクティス
iOSアプリを開発する際は、Citrix Endpoint Management™とiOSデバイス向けモバイルアプリ間の互換性を向上させるために、これらのベストプラクティスを使用してください。
MDX App SDK Frameworkとラッピング
アプリがMDX App SDK Frameworkを使用している場合、ラッピングには対応するMDX Toolkitバージョンを使用する必要があります。これら2つのコンポーネント間のバージョン不一致は、不適切な動作を引き起こす可能性があります。
このような不一致を防ぐには、アプリをISVアプリとしてラッピングし、アプリモードをPremiumまたはGeneralに指定します。これにより、事前にラッピングされたアプリを提供できます。その結果、顧客はアプリをラッピングする必要がなくなり、不一致のMDX Toolkitの使用を回避できます。ISVラッピングの詳細については、「iOSモバイルアプリのラッピング」を参照してください。
明示的なアプリIDの使用
iOS Developer EnterpriseアカウントがワイルドカードApp IDをサポートしていない場合は、MDX Toolkitでラッピングする予定の各アプリに対して明示的なApp IDを作成してください。また、各App IDに対してプロビジョニングプロファイルを作成してください。
-
メインスレッドのブロック回避
メインスレッドで実行中にブロッキングコードを使用しないでください。これはAppleのガイドラインですが、Citrix Endpoint Managementではさらに重要です。一部のアクションは、管理対象アプリでより多くの時間を要したり、さらなるスレッド実行をブロックしたりする可能性があります。ファイル、データベース、ネットワーク操作は、現在実行中のスレッドをブロックする可能性のある操作の例であり、メインスレッドでは避けるべきです。
-
堅牢なコードの記述
-
特に、Appleアプリケーションプログラミングガイドなど、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 Promptインタラクションを提供するため、アプリでそれを行う必要はありません。
Citrix Endpoint Managementの準備を確実にするために、Objective-Cランタイムセレクターをリダイレクトまたは置換しないことをお勧めします。その理由は、Citrix Endpoint Managementがいくつかのオブジェクトクラスセレクターの基盤となるメソッドをスウィズルして、アプリのランタイム動作を制御または変更するためです。次の表に、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
-
セレクター名:
devices
devicesWithMediaType:
オブジェクトクラス名: AVAsset
- セレクター名: assetWithURL:
オブジェクトクラス名: AVURLAsset
-
セレクター名:
initWithURL:options:
URLAssetWithURL:options:
オブジェクトクラス名: AVPlayerItem
-
セレクター名:
playerItemWithAsset:
initWithURL:
playerItemWithURL:
オブジェクトクラス名: AVPlayer
-
セレクター名:
playerWithPlayerItem:
initWithPlayerItem:
initWithURL:
オブジェクトクラス名: CLLocationManager
-
セレクター名: startUpdatingLocation
-
オブジェクトクラス名: UIScrollView
-
セレクター名: setContentOffset:
オブジェクトクラス名: MFMailComposeViewController
-
セレクター名:
-
canSendMail
init
オブジェクトクラス名: 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:
items
itemSetWithPasteboardTypes:
dataForPasteboardType:inItemSet:
valuesForPasteboardType:inItemSet:
string
strings
URL
URLs
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ランタイム内で、かつObjective-Cランタイム専用に実装されたファイルデータ暗号化は、容易に回避される可能性があります。
-
AVPlayerクラス、UIWebViewクラス、QLPreviewControllerなどの一部のフレームワークAPIは、ユーザーの管理対象アプリプロセスとは異なる実行コンテキストでiOSサービスプロセスによって実装されます。
これらのサービスプロセスは、MDXで暗号化されたファイルデータを復号化できません。そのため、管理対象アプリは、サービスプロセスにデータの一時的な非暗号化コピーを提供する必要があります。このコピーは、5秒後に管理対象アプリによって削除されます。これらのクラスを使用する際には、この制限を認識しておくことが重要です。その理由は、Appleが特定のクラスを実装しているため、これらのクラスに提供されるデータのコンテインメント制御が失われるためです。
-
メモリマッピングは、Citrix Endpoint Managementの暗号化にとって問題となります。これは、アプリがファイルI/Oシステムコールインターフェースを呼び出すことに依存しているためです。
ファイルがメモリマップされると、ファイルのI/O要求はユーザーアプリのコンテキスト外で管理され、Citrix Endpoint Managementの暗号化をバイパスします。管理対象アプリによるすべてのPOSIX mmap(2)呼び出しは、MAP_PRIVATEおよびMAP_ANONとしてマップされ、どのファイル記述子とも関連付けられません。ファイル記述子が指定されている場合、mmap呼び出し中にマップされたすべてのデータを読み込もうとします。これは、オペレーティングシステムによるその後のデータのページインが、Citrix Endpoint Managementによって復号化されない暗号化されたデータを読み込む結果となるためです。この手法は、Citrix Endpoint Managementでテストされたすべてのアプリで成功しています。これは、メモリマップされるデータ量が少なく、アプリ内でメモリページが再利用されることがないためです。
-
暗号化は測定可能なオーバーヘッドを追加します。開発者は、パフォーマンスの低下を防ぐためにディスクI/Oを最適化する必要があります。たとえば、同じ情報を繰り返し読み書きしている場合、アプリレベルのキャッシュを実装することを検討してください。
-
Citrix Endpoint Managementは、Apple libsqlite.dylibのインスタンスのみを暗号化します。アプリケーションがlibsqlite.dylibのプライベートバージョンに直接リンクしている、および/または埋め込んでいる場合、そのプライベートライブラリのデータベースインスタンスはCitrix Endpoint Managementによって暗号化されません。
-
Apple SQLiteデータベースは、Citrix Endpoint ManagementによってSQLite仮想ファイルシステム層を使用して暗号化されます。
パフォーマンスが問題となる場合があります。標準のデータベースキャッシュサイズは2000ページまたは8メガバイトです。データベースが大きい場合、開発者はデータベースキャッシュサイズを増やすためにSQLiteプラグマを指定する必要があるかもしれません。Objective-C Core Dataフレームワークでは、永続ストアオブジェクトを永続ストアコントローラーオブジェクトに追加する際に、SQLiteプラグマをオプション辞書として追加できます。
-
SQLite WALモードは、ライブラリがファイルI/Oインターフェースに再リンクされ、内部でメモリマッピングを広範囲に使用するため、サポートされていません。
-
NSURLCache DiskCacheは、iOSによってSQLiteデータベースを使用して実装されます。Citrix Endpoint Managementは、このデータベースが管理対象外のiOSサービスプロセスによって参照されるため、関連するディスクキャッシュを無効にします。
-
以下は、ハードコードされた除外ファイルパス名パターンのリストです。
- .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オブジェクトクラスがネイティブにサポートしていないいくつかのファイル形式をネイティブにサポートしています。
-
最高のパフォーマンスを得るには、ファイルI/O要求は4096バイトの倍数であるファイルオフセットに対して発行され、長さも4096バイトの倍数である必要があります。
-
O_NONBLOCKファイルモードフラグは、Citrix Endpoint Managementの暗号化ではサポートされていません。このファイルモードフラグは、Citrix Endpoint Managementによって処理される際にモードのリストから削除されます。
暗号化ユーザーエントロピー
Citrix Endpoint Managementの暗号化オプションの1つは、暗号化キーを生成する前にエンドユーザーがPINを入力することを要求します。このオプションはユーザーエントロピーと呼ばれます。これはアプリに特定の問題を引き起こす可能性があります。
具体的には、ユーザーがPINを入力するまで、ファイルまたはデータベースへのアクセスは実行できません。このようなI/O操作が、PIN UIが表示される前に実行される場所にある場合、常に失敗します。
この問題がアプリに存在しないことを確認するには、ユーザーエントロピーを有効にしてテストします。Citrix Endpoint Managementクライアントプロパティの「パスコードを使用してシークレットを暗号化」は、ユーザーエントロピーを追加します。このクライアントプロパティは、Citrix Endpoint Managementコンソールの [構成] > [設定] > [詳細] > [クライアントプロパティ] で構成しますが、デフォルトでは無効になっています。
データコンテインメントの互換性
- リモートビューコントローラーは、MDX管理対象アプリとは異なるプロセスコンテキストで実行されるため、セキュリティコンテインメント(データ暗号化、コピー、切り取り、貼り付けポリシーのブロックなど)を持ちません。
- [コピー] アクションは、UIResponderからサポートされる唯一のアクションです。[切り取り] や [削除] などの他のアクションはサポートされていません。
- AirDropはUIレベルでのみインターセプトされ、下位レベルではインターセプトされません。
- MFIおよびBluetoothはインターセプトされません。
アイコンファイルのサポート
MDXラッピングには、ホーム画面アイコンまたはアプリアイコンとして使用できるアイコンが少なくとも1つ必要です。アプリ開発者は、Asset Catalogにアイコンを追加するか、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
ネットワークとマイクロVPN
MDXは現在、アプリによって直接発行されたネットワーク呼び出しのみを管理します。一部のDNSクエリはAppleフレームワークによって直接発行されるため、MDXでは管理されません。
Citrix Endpoint Managementには、管理者がネットワーク用に利用できるいくつかのポリシーオプションがあります。
ネットワークアクセスポリシーは、アプリのネットワークアクティビティを防止、許可、またはリダイレクトします。
重要:
MDX Toolkitバージョン18.12.0リリースには、以前のポリシーを組み合わせたり置き換えたりする新しいポリシーが含まれています。 ネットワークアクセスポリシーは、ネットワークアクセス、優先VPNモード、およびVPNモード切り替えの許可を組み合わせたものです。除外リストポリシーは、スプリットトンネル除外リストを置き換えます。マイクロVPNセッション必須ポリシーは、オンラインセッション必須を置き換えます。詳細については、「以前のリリースでの新機能」を参照してください。
「トンネル化 - Web SSO」は、設定におけるセキュアブラウズの名称です。動作は同じです。
オプションは次のとおりです。
- 以前の設定を使用: 以前のポリシーで設定した値にデフォルト設定されます。このオプションを変更した場合、以前の設定を使用に戻すべきではありません。また、新しいポリシーへの変更は、ユーザーがアプリをバージョン18.12.0以降にアップグレードするまで有効になりません。
- ブロック済み: アプリが使用するネットワークAPIは失敗します。以前のガイドラインに従い、このような失敗は適切に処理する必要があります。
- 無制限: すべてのネットワーク呼び出しは直接行われ、トンネル化されません。
- トンネル化 - フルVPN: 管理対象アプリからのすべてのトラフィックはCitrix Gatewayを介してトンネル化されます。
- トンネル化 - Web SSO: HTTP/HTTPS URLが書き換えられます。このオプションは、HTTPおよびHTTPSトラフィックのトンネル化のみを許可します。トンネル化 - Web SSOの大きな利点は、HTTPおよびHTTPSトラフィックのシングルサインオン(SSO)とPKINIT認証です。Androidでは、このオプションはセットアップのオーバーヘッドが低いため、Webブラウジングタイプの操作に推奨されるオプションです。
- トンネル化 - フルVPNとWeb SSO: 必要に応じてVPNモード間の自動切り替えを許可します。特定のVPNモードで処理できない認証要求のためにネットワーク要求が失敗した場合、別のモードで再試行されます。
制限事項
- MDXがインターセプトしないデバイス上のメディアプレーヤープロセスでビデオが再生されるため、iOSでラップされたMDXアプリでは、ユーザーは内部Webサイトでホストされているビデオを再生できません。
- NSURLSessionバックグラウンドダウンロード(NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier)はサポートされていません。
- ネットワークアクセスポリシーがブロック済みに設定されている場合、UDPトラフィックはブロックされます。ネットワークアクセスポリシーがトンネル化 - フルVPNに設定されている場合、UDPトラフィックはトンネル化されません。
- MDXでラップされたアプリは、インバウンド接続をリッスンするソケットサーバーをインスタンス化できません。ただし、MDXでラップされたアプリは、クライアントソケットを使用してサーバーに接続できます。
サードパーティライブラリのサポート
一部のアプリフレームワークには、Citrix Endpoint Managementとの互換性の問題があります。
- Xamarinクロスプラットフォーム開発環境で開発されたアプリはサポートされています。Citrixは、使用例とテストが不十分であるため、他のクロスプラットフォーム開発環境のサポートを公式には宣言していません。
- SQLCipherはメモリマッピングを使用するため、暗号化では機能しません。1つの解決策は、SQLCipherを使用しないことです。2つ目の解決策は、暗号化除外ポリシーを使用してデータベースファイルを暗号化から除外することです。Citrix Endpoint Management管理者は、Citrix Endpoint Managementコンソールでポリシーを構成する必要があります。
- OpenSSL libcrypto.aおよびlibssl.aライブラリに直接リンクするアプリおよびサードパーティライブラリは、シンボルの欠落によるリンクエラーや、複数のシンボル定義によるリンクエラーを引き起こす可能性があります。
- Apple Push Notification Serviceのサポートを必要とするアプリは、Appleが要求する特定のステップに従う必要があります。
- Citrix Endpoint Managementは、SQLiteデータベースバージョンを明示的に1に設定して、SQLiteデータベース内のWrite Ahead Logging(WAL)ファイルおよびメモリマップファイルサポートを無効にします。SQLiteバージョン2またはバージョン3でSQLiteインターフェースに直接アクセスしようとすると失敗します。