PageSense iOS SDK — React Nativeブリッジ連携ガイド

PageSense iOS SDK — React Nativeブリッジ連携ガイド

お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。

概要  

このガイドでは、React Nativeネイティブブリッジを使用して、PageSense iOS SDKをReact Nativeアプリケーションに統合する方法について説明します。このブリッジにより、React NativeのJavaScriptコードからiOS SDKの関数を呼び出し、モバイルアプリケーション内でフルスタックのテスト機能を利用できます。
このガイドを完了すると、React Nativeアプリケーションから、JavaScriptを使用してPageSense SDKの次の関数を直接呼び出せるようになります。
  • initialiseSDK
  • activateExperimentByContext
  • getVariationNameByContext
  • trackGoalByContext

React Nativeネイティブブリッジとは  

React Nativeネイティブブリッジは、JavaScriptランタイムとiOSのネイティブコードの間にある通信レイヤーです。これにより、JavaScriptからネイティブ関数を呼び出し、プラットフォーム固有のSDK機能にアクセスして、ネイティブモジュールから応答を受け取ることができます。
JavaScriptはSwiftと直接やり取りできないため、React Nativeではブリッジが仲介役となります。ネイティブメソッドはSwiftで実装され、Objective-Cブリッジファイルを通じてReact Nativeに公開されます。

IdeaReact Native UI

React Nativeラッパー(TypeScript/JavaScript)

React Nativeネイティブブリッジ

Objective-Cブリッジモジュール(.m)

Swiftネイティブモジュール(.swift)

PageSense iOS SDK

ネイティブモジュールはSwiftで実装され、Objective-Cブリッジファイルを通じてReact NativeのJavaScriptレイヤーに公開されます。登録後、このモジュールにはReact NativeのNativeModulesAPIからアクセスできます。

前提条件  

  • Node.js
  • npm
  • React Native CLI
  • Xcode
  • CocoaPods
bash
node-v
npm-v
pod --version

PageSense iOS SDKのインストール  

PageSense iOS SDKはXCFrameworkとして配布されています。
  1. PageSenseFramework.xcframework.zip」を、ZohoPageSenseSDKリポジトリーのFrameworksフォルダーからダウンロードし、内容を展開します。
  2. 展開したフレームワークをiOSプロジェクトのフォルダーに配置します。
/ProjectRoot/ios/Frameworks/PageSenseFramework.xcframework
  1. Xcodeでワークスペースを開き、次の場所に移動します。
[ターゲット]→[一般]→[フレームワーク、ライブラリ、埋め込みコンテンツ]
  1. PageSenseFramework.xcframework」を追加し、選択肢を[埋め込みと署名]に設定します。

iOS用React Nativeライブラリ  

次のReact Nativeライブラリが必要です。これらは、pod installiosディレクトリーから実行すると、自動的にインストールされます。
  • React-Core
  • React-RCTBridge
  • React-RCTNetwork
  • React-RCTText
  • React-RCTImage
React Nativeブリッジを実装するには、次のiOSフレームワーク依存関係が必要です。
  • React
  • RCTBridgeModule
  • Foundation

ネイティブブリッジモジュールの作成  

iOSネイティブブリッジは、SwiftネイティブモジュールとObjective-Cブリッジファイルの2つの部分で実装します。

パート1 — Swiftネイティブモジュール  

PageSenseSDKModule.swift」をiOSアプリケーションのディレクトリー内に作成します。
  1. /ProjectRoot/ios/SampleApp/PageSenseSDKModule.swift
  2. swift
  3. import Foundation
  4. import React
  5. import PageSenseFramework
  6. @objc(PageSenseSDKModule)
  7. class PageSenseSDKModule: NSObject {
  8.     private varclient: PageSenseClient?
  9.     private varisInitialized: Bool= false
  10.     private static let LOG_TAG= '[PageSenseSDK]'
  11.     @objc
  12.     static func requiresMainQueueSetup()-> Bool {
  13.         return false
  14.     }
  15.     @objc
  16.     func initialiseSDK(
  17.         _accountId: String,
  18. sdkKey: String,
  19. projectName: String,
  20. resolver resolve: @escaping RCTPromiseResolveBlock,
  21. rejecter reject: @escaping RCTPromiseRejectBlock
  22.     ) {
  23.         if self.isInitialized { resolve(true); return }
  24.         letpageSenseSDKOptions = PageSenseSDKOptions()
  25. pageSenseSDKOptions.logLevel = .DEBUG
  26. pageSenseSDKOptions.pollingInterval = 5
  27.         PageSense.shared.createNewPageSenseClient(
  28. sdkAccountIDForDC:accountId,
  29. sdkKey:sdkKey,
  30. projectname:projectName,
  31. sdkOptions:pageSenseSDKOptions
  32.         ) {pagesenseclient in
  33.             guard letclient = pagesenseclient else { resolve(false); return }
  34.             self.client = client
  35.             self.isInitialized = true
  36.             resolve(true)
  37.         }
  38.     }
  39.     @objc
  40.     func activateExperimentByContext(
  41.         _experimentName: String,
  42. userContext: NSDictionary,
  43. resolver resolve: @escaping RCTPromiseResolveBlock,
  44. rejecter reject: @escaping RCTPromiseRejectBlock
  45.     ) {
  46.         guard letclient = self.client,
  47.               letpageSenseUserContext = validateAndBuildUserContext(userContext) else {
  48.             resolve(nil); return
  49.         }
  50. client.activateExperiment(experimentName:experimentName,userContext:pageSenseUserContext) {variation in
  51.             resolve(variation)
  52.         }
  53.     }
  54.     @objc
  55.     func getVariationNameByContext(
  56.         _experimentName: String,
  57. userContext: NSDictionary,
  58. resolver resolve: @escaping RCTPromiseResolveBlock,
  59. rejecter reject: @escaping RCTPromiseRejectBlock
  60.     ) {
  61.         guard letclient = self.client,
  62.               letpageSenseUserContext = validateAndBuildUserContext(userContext) else {
  63.             resolve(nil); return
  64.         }
  65.         resolve(client.getVariationName(experimentName:experimentName,userContext:pageSenseUserContext))
  66.     }
  67.     @objc
  68.     func trackGoalByContext(_goalName: String,userContext: NSDictionary) {
  69.         guard letclient = self.client,
  70.               letpageSenseUserContext = validateAndBuildUserContext(userContext) else { return }
  71. client.trackGoal(goalName:goalName,userContext:pageSenseUserContext)
  72.     }
  73.     @objc
  74.     func trackGoalWithPropertiesByContext(
  75.         _goalName: String,
  76. userContext: NSDictionary,
  77. goalProperties: NSDictionary
  78.     ) {
  79.         guard letclient = self.client,
  80.               letpageSenseUserContext = validateAndBuildUserContext(userContext),
  81.               letgoalPropertiesMap = validateAndConvertGoalPropertiesNonEmpty(goalProperties) else { return }
  82. client.trackGoal(goalName:goalName,userContext:pageSenseUserContext,goalProperties:goalPropertiesMap)
  83.     }
  84.     private func validateAndBuildUserContext(_userContextDict: NSDictionary)-> PageSenseUserContext? {
  85.         guard letuserId = userContextDict['userId'] as? String,
  86. !userId.trimmingCharacters(in: .whitespaces).isEmpty else { return nil }
  87.         varuserAttributes: [String: String]= [:]
  88.         if letrawAttrs = userContextDict['userAttributes'] as? NSDictionary {
  89.             for (key,value) inrawAttrs {
  90.                 guard letk = key as? String, letv = value as? String else { return nil }
  91. userAttributes[k]= v
  92.             }
  93.         }
  94.         return PageSenseUserContext(userId:userId,userAttributes:userAttributes)
  95.     }
  96.     private func validateAndConvertGoalPropertiesNonEmpty(_goalPropertiesDict: NSDictionary)-> [GoalProperty: String]? {
  97.         ifgoalPropertiesDict.count == 0 { return nil }
  98.         varresult: [GoalProperty: String]= [:]
  99.         for (key,value) ingoalPropertiesDict {
  100.             guard letkeyString = key as? String,
  101.                   letgoalProperty = GoalProperty(rawValue:keyString),
  102.                   letvalueString = value as? String else { return nil }
  103. result[goalProperty]= valueString
  104.         }
  105.         returnresult
  106.     }
  107. }
パート2 — Objective-Cブリッジファイル  

同じディレクトリーにPageSenseSDKModule.mを作成します。
  1. /ProjectRoot/ios/SampleApp/PageSenseSDKModule.m
  2. objc
  3. #import <React/RCTBridgeModule.h>
  4. @interface RCT_EXTERN_MODULE(PageSenseSDKModule,NSObject)
  5. RCT_EXTERN_METHOD(initialiseSDK:(NSString *)accountId
  6. sdkKey:(NSString *)sdkKey
  7. projectName:(NSString *)projectName
  8. resolver:(RCTPromiseResolveBlock)resolve
  9. rejecter:(RCTPromiseRejectBlock)reject)
  10. RCT_EXTERN_METHOD(activateExperimentByContext:(NSString *)experimentName
  11. userContext:(NSDictionary *)userContext
  12. resolver:(RCTPromiseResolveBlock)resolve
  13. rejecter:(RCTPromiseRejectBlock)reject)
  14. RCT_EXTERN_METHOD(getVariationNameByContext:(NSString *)experimentName
  15. userContext:(NSDictionary *)userContext
  16. resolver:(RCTPromiseResolveBlock)resolve
  17. rejecter:(RCTPromiseRejectBlock)reject)
  18. RCT_EXTERN_METHOD(trackGoalByContext:(NSString *)goalName
  19. userContext:(NSDictionary *)userContext)
  20. RCT_EXTERN_METHOD(trackGoalWithPropertiesByContext:(NSString *)goalName
  21. userContext:(NSDictionary *)userContext
  22. goalProperties:(NSDictionary *)goalProperties)
  23. @end
Objective-Cブリッジヘッダーの追加  

SwiftとObjective-Cの間の通信を有効にするには、次の手順を実行します。
  1. 次の場所にブリッジヘッダーファイルを作成します。
/ProjectRoot/ios/SampleApp/SampleApp-Bridging-Header.h
  1. Xcodeでプロジェクトを開き、[ビルド設定]に移動します。
  2. [Objective-Cブリッジヘッダー]を見つけ、値を次のように設定します。
SampleApp/SampleApp-Bridging-Header.h

GoalPropertyのマッピング  


iOSでは、PageSense SDKは目標プロパティを[GoalProperty: String]形式で受け取ります。ここで、GoalPropertyPageSenseFrameworkによって公開されている列挙型で、raw値は小文字です。React Nativeブリッジは、JavaScriptから目標プロパティを文字列のキーと値のペアで構成されたNSDictionaryとして受け取り、小文字の各文字列キーを、対応するGoalProperty列挙型のケースにGoalProperty(rawValue:)を使用してマッピングします。
JavaScriptキー
文字列値
iOSのGoalProperty列挙型のケース
GoalProperty.REVENUE
'revenue'
GoalProperty.revenue

ベストプラクティス  

  • プロジェクトのSDK初期化は、アプリケーションのライフサイクルごとに1回のみ、テストを有効化する前に行ってください。
  • SDKの初期化に失敗しても、UIのレンダリングをブロックしないでください。必ずフォールバックUIを使用してください。
  • PageSenseClientインスタンスは、アプリケーションセッション全体で保持してください。
  • ユーザーごとに一意のユーザーIDを作成し、全体で再利用してください。
  • PageSenseUserContextはユーザーセッションごとに1回だけ構築し、SDKの呼び出し全体で再利用してください。
  • 売上目標を追跡する場合は、売上の値をセント単位の文字列として必ず渡してください。ドル金額に100を掛け、最も近い整数に丸めます。
  • ハードコードされた文字列ではなく、JavaScriptラッパーからエクスポートされるGoalProperty定数を使用してください。小文字の文字列値は、iOSのGoalProperty列挙型のraw値に直接マッピングされます。
  • バリエーションがnullの場合は、常に安全なデフォルトUIにフォールバックしてください。
  • ネイティブモジュールには、UIの状態ではなく、SDK関連のオブジェクトのみを保存してください。
  • 特定のユーザー処理またはイベントが正常に完了した後に、目標をトリガーしてください。
  • すべての新規連携では、コンテキストベースのSDK関数(activateExperimentByContextgetVariationNameByContexttrackGoalByContext)を使用してください。



このドキュメントは、各手順をわかりやすくご案内できるよう構成されています。さらにサポートが必要な場合やご質問がある場合は、support@zohopagesense.com - までお気軽にお問い合わせください。いつでもサポートいたします。