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

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

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

概要  

このガイドでは、React Native Native Bridgeを使用して、PageSense Android SDKをReact Nativeアプリケーションに組み込む方法を説明します。このブリッジにより、React NativeのJavaScriptコードからAndroid SDKの関数を呼び出し、モバイルアプリケーションでFullStack実験機能を使用できます。
このガイドを完了すると、React NativeアプリケーションのJavaScriptから次のPageSense SDK関数を直接呼び出せるようになります。
  • initialiseSDK
  • activateExperimentByContext
  • getVariationNameByContext
  • trackGoalByContext

React Native Native Bridgeとは  

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


IdeaReact Native UI

React Nativeラッパー(TypeScript/JavaScript)

React Native Native Bridge

PageSenseSDKPackage(モジュール登録)

PageSenseSDKModule(Kotlinネイティブモジュール)

PageSense Android SDK

React Nativeアプリケーションは主にJavaScriptを実行しますが、PageSense Android SDKはKotlinで実装されています。ネイティブモジュールは、PageSense SDKのメソッドをReact NativeのJavaScriptレイヤーに公開します。React Nativeランタイムに登録されると、このモジュールにはReact NativeのNativeModules APIを通じてアクセスできるようになります。

前提条件  

SDKを組み込む前に、次のツールがインストールされていることを確認してください。

開発環境
  • Node.js
  • npm
  • Watchman
  • React Native CLI
Android開発ツール
  • Android Studio
  • Android SDK
  • Gradle
  • Java Development Kit(JDK)
bash
node-v
npm-v
npx react-native doctor

PageSense Android SDKのインストール  

PageSense Android SDKはZoho Maven Repositoryを通じて配布されています。

ステップ1 — Zoho Maven Repositoryの追加  

最近のReact Nativeプロジェクト(Gradle 7以降)では、settings.gradleにリポジトリーを追加します。
  1. gradle
  2. dependencyResolutionManagement {
  3. repositories {
  4. google()
  5. mavenCentral()
  6. maven {
  7. url 'https://maven.zohodl.com/'
  8. }
  9. }
  10. }
一部のプロジェクト設定では、プロジェクトレベルのbuild.gradleにリポジトリーを追加する場合もあります。
  1. gradle
  2. repositories {
  3. google()
  4. mavenCentral()
  5. maven {
  6. url 'https://maven.zohodl.com/'
  7. }
  8. }
ステップ2 — PageSense Android SDKの依存関係の追加  

android/app/build.gradle:に依存関係を追加します
  1. gradle
  2. dependencies {
  3. implementation('com.facebook.react:react-android')
  4. implementation('com.zoho.pagesense:pagesense:1.1.3')
  5. }

Android向けReact Nativeライブラリー  

次のReact Nativeライブラリーは必須であり、Androidビルド設定の一部として自動的に含まれます。
  • react-android — Android向けReact Nativeのコアランタイムライブラリー。
  • hermes-android(任意)— パフォーマンス向上のためのJavaScriptエンジン。
ネイティブモジュールを実装するには、次のReact Nativeブリッジライブラリーを利用できる必要があります。
  • ReactContextBaseJavaModule
  • ReactMethod
  • Promise
  • ReadableMap
  • ReactPackage
  • ReactApplicationContext

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

Androidネイティブブリッジは、Kotlinネイティブモジュール、React Nativeパッケージ、パッケージ登録の3つの部分で実装します。

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

AndroidアプリケーションのJavaソースパッケージ内にPageSenseSDKModule.ktを作成します。
  1. /ProjectRoot/android/app/src/main/java/com/sampleapp/PageSenseSDKModule.kt
  2. kotlin
  3. packagecom.sampleapp
  4. importcom.facebook.react.bridge.*
  5. importcom.facebook.react.module.annotations.ReactModule
  6. importcom.zoho.pagesense.android.abtesting.PageSenseClient
  7. importcom.zoho.pagesense.android.abtesting.PageSenseClientBuilder
  8. importcom.zoho.pagesense.android.abtesting.PageSenseSDKOptions
  9. importcom.zoho.pagesense.android.abtesting.data.PageSenseUserContext
  10. importcom.zoho.pagesense.android.network.ProjectSettingsCallBack
  11. importcom.zoho.pagesense.android.logging.LogLevel
  12. importcom.zoho.pagesense.android.abtesting.constants.GoalProperty
  13. @ReactModule(name = PageSenseSDKModule.NAME)
  14. class PageSenseSDKModule(private valreactContext: ReactApplicationContext):
  15.     ReactContextBaseJavaModule(reactContext) {
  16.     companion object {
  17.         const valNAME = 'PageSenseSDKModule'
  18.         private const valLOG_TAG = '[PageSenseSDK]'
  19.     }
  20.     private varclient: PageSenseClient? = null
  21.     private varisInitialized = false
  22.     override fun getName(): String {
  23.         returnNAME
  24.     }
  25.     @ReactMethod
  26.     fun initialiseSDK(
  27. accountId: String,
  28. sdkKey: String,
  29. projectName: String,
  30. promise: Promise
  31.     ) {
  32.         if (isInitialized) {
  33.             println('$LOG_TAGSDK already initialized')
  34. promise.resolve(true)
  35.             return
  36.         }
  37.         if (!validateString(accountId, 'accountId')||
  38. !validateString(sdkKey, 'sdkKey')||
  39. !validateString(projectName, 'projectName')) {
  40. promise.resolve(false)
  41.             return
  42.         }
  43.         valpageSenseSDKOptions = PageSenseSDKOptions()
  44. pageSenseSDKOptions.logLevel = LogLevel.DEBUG
  45. pageSenseSDKOptions.pollingInterval = 5
  46. PageSenseClientBuilder.createNewPageSenseClient(
  47. accountId,
  48. sdkKey,
  49. projectName,
  50. pageSenseSDKOptions,
  51.             object: ProjectSettingsCallBack {
  52.                 override fun onFailure(message: String?,code: Int?) {
  53. promise.resolve(false)
  54.                 }
  55.                 override fun onSuccess(data: PageSenseClient?) {
  56.                     if (data!= null) {
  57. client = data
  58. isInitialized = true
  59. promise.resolve(true)
  60.                     } else {
  61. promise.resolve(false)
  62.                     }
  63.                 }
  64.             }
  65.         )
  66.     }
  67.     @ReactMethod
  68.     fun activateExperimentByContext(
  69. experimentName: String,
  70. userContextMap: ReadableMap,
  71. promise: Promise
  72.     ) {
  73.         valclientInstance = client
  74.         if (clientInstance == null) {promise.resolve(null); return }
  75.         if (!validateString(experimentName, 'experimentName')) {promise.resolve(null); return }
  76.         valuserContext = validateAndBuildUserContext(userContextMap)
  77.         if (userContext == null) {promise.resolve(null); return }
  78.         try {
  79. promise.resolve(clientInstance.activateExperiment(experimentName,userContext))
  80.         } catch (e: Exception) {promise.resolve(null) }
  81.     }
  82.     @ReactMethod
  83.     fun getVariationNameByContext(
  84. experimentName: String,
  85. userContextMap: ReadableMap,
  86. promise: Promise
  87.     ) {
  88.         valclientInstance = client
  89.         if (clientInstance == null) {promise.resolve(null); return }
  90.         if (!validateString(experimentName, 'experimentName')) {promise.resolve(null); return }
  91.         valuserContext = validateAndBuildUserContext(userContextMap)
  92.         if (userContext == null) {promise.resolve(null); return }
  93.         try {
  94. promise.resolve(clientInstance.getVariationName(experimentName,userContext))
  95.         } catch (e: Exception) {promise.resolve(null) }
  96.     }
  97.     @ReactMethod
  98.     fun trackGoalByContext(goalName: String,userContextMap: ReadableMap) {
  99.         valclientInstance = client ?: return
  100.         if (!validateString(goalName, 'goalName')) return
  101.         valuserContext = validateAndBuildUserContext(userContextMap)?: return
  102.         try {clientInstance.trackGoal(goalName,userContext) } catch (e: Exception) { }
  103.     }
  104.     @ReactMethod
  105.     fun trackGoalWithPropertiesByContext(
  106. goalName: String,
  107. userContextMap: ReadableMap,
  108. goalPropertiesMap: ReadableMap
  109.     ) {
  110.         valclientInstance = client ?: return
  111.         if (!validateString(goalName, 'goalName')) return
  112.         valuserContext = validateAndBuildUserContext(userContextMap)?: return
  113.         valgoalProperties = validateAndConvertGoalPropertiesNonEmpty(goalPropertiesMap)?: return
  114.         try {clientInstance.trackGoal(goalName,userContext,goalProperties) } catch (e: Exception) { }
  115.     }
  116.     private fun validateString(param: String,paramName: String): Boolean {
  117.         if (param.trim().isEmpty()) {
  118.             println('$LOG_TAG無効な $paramName:空でない文字列である必要があります')
  119.             return false
  120.         }
  121.         return true
  122.     }
  123.     private fun validateAndBuildUserContext(userContextMap: ReadableMap): PageSenseUserContext? {
  124.         if (!userContextMap.hasKey('userId')) return null
  125.         valuserId = userContextMap.getString('userId')
  126.         if (userId.isNullOrBlank()) return null
  127.         valuserAttributes = HashMap<String,String>()
  128.         if (userContextMap.hasKey('userAttributes')&& !userContextMap.isNull('userAttributes')) {
  129.             valrawAttrs = userContextMap.getMap('userAttributes')?: return null
  130.             valiterator = rawAttrs.keySetIterator()
  131.             while (iterator.hasNextKey()) {
  132.                 valkey = iterator.nextKey()
  133.                 if (key.trim().isEmpty()) return null
  134.                 if (rawAttrs.getType(key)!= ReadableType.String) return null
  135. userAttributes[key]= rawAttrs.getString(key)?: return null
  136.             }
  137.         }
  138.         return PageSenseUserContext(userId,userAttributes)
  139.     }
  140.     private fun validateAndConvertGoalPropertiesNonEmpty(
  141. goalPropertiesMap: ReadableMap
  142.     ): HashMap<GoalProperty,String>? {
  143.         valresult = HashMap<GoalProperty,String>()
  144.         valiterator = goalPropertiesMap.keySetIterator()
  145.         if (!iterator.hasNextKey()) return null
  146.         valfreshIterator = goalPropertiesMap.keySetIterator()
  147.         while (freshIterator.hasNextKey()) {
  148.             valkey = freshIterator.nextKey()
  149.             if (key.trim().isEmpty()) return null
  150.             if (goalPropertiesMap.getType(key)!= ReadableType.String) return null
  151.             valvalue = goalPropertiesMap.getString(key)?: return null
  152.             valgoalProperty = when (key.lowercase()) {
  153. GoalProperty.REVENUE.value -> GoalProperty.REVENUE
  154.                 else-> return null
  155.             }
  156. result[goalProperty]= value
  157.         }
  158.         returnresult
  159.     }
  160. }
パート2 — React Nativeパッケージ  

同じディレクトリーにPageSenseSDKPackage.ktを作成します。
  1. /ProjectRoot/android/app/src/main/java/com/sampleapp/PageSenseSDKPackage.kt
  2. kotlin
  3. packagecom.sampleapp
  4. importcom.facebook.react.ReactPackage
  5. importcom.facebook.react.bridge.NativeModule
  6. importcom.facebook.react.bridge.ReactApplicationContext
  7. importcom.facebook.react.uimanager.ViewManager
  8. classPageSenseSDKPackage : ReactPackage {
  9.     override fun createNativeModules(
  10. reactContext: ReactApplicationContext
  11.     ): List<NativeModule> {
  12.         return listOf(PageSenseSDKModule(reactContext))
  13.     }
  14.     override fun createViewManagers(
  15. reactContext: ReactApplicationContext
  16.     ): List<ViewManager<*,*>> {
  17.         return emptyList()
  18.     }
  19. }
  20. パート3—パッケージの登録  
  21. MainApplication.ktでパッケージを登録します。
  22. kotlin
  23. packagecom.sampleapp
  24. importandroid.app.Application
  25. importcom.facebook.react.PackageList
  26. importcom.facebook.react.ReactApplication
  27. importcom.facebook.react.ReactHost
  28. importcom.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
  29. importcom.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
  30. importcom.sampleapp.PageSenseSDKPackage
  31. classMainApplication : Application(),ReactApplication {
  32.     override valreactHost: ReactHost bylazy {
  33.         getDefaultReactHost(
  34. context = applicationContext,
  35. packageList =
  36.                 PackageList(this).packages.apply {
  37.                     add(PageSenseSDKPackage())
  38.                 },
  39.         )
  40.     }
  41.     override fun onCreate() {
  42.         super.onCreate()
  43.         loadReactNative(this)
  44.     }
  45. }
GoalPropertyのマッピング  

Androidでは、PageSense SDKはゴールプロパティをHashMap<GoalProperty, String>として受け取ります。ここで、GoalPropertyはcom.zoho.pagesense.android.abtesting.constantsで定義されている定数クラスです。React Nativeブリッジは、JavaScriptから文字列キー/valueのペアのReadableMapとしてゴールプロパティを受け取り、各文字列キーを対応するGoalProperty定数にマッピングします。

JavaScriptキー
文字列値
AndroidのGoalProperty定数
GoalProperty.REVENUE
'revenue'
GoalProperty.REVENUE

ベストプラクティス  

  • プロジェクトでは、アプリケーションのライフサイクルごとにSDKを1回だけ初期化してください。
  • 実験をすぐに利用できるように、アプリケーションの起動時にSDKを初期化してください。
  • SDKの初期化に失敗しても、UIのレンダリングをブロックしないでください。必ず代替UIを使用してください。
  • アプリケーションセッション全体でPageSenseClientインスタンスを維持してください。
  • 実験を適切に追跡できるように、アプリケーションセッション全体で一貫したユーザーIDを使用してください。
  • ユーザーセッションごとにPageSenseUserContextを1回作成し、SDK呼び出し全体で再利用してください。
  • 収益ゴールを追跡する場合は、収益値を必ずセント単位の文字列として渡してください。ドル金額に100を掛け、最も近い整数に丸めてください。
  • ハードコードされた文字列ではなく、JavaScriptラッパーからエクスポートされたGoalProperty定数を使用してください。
  • バリエーションがnullの場合は、常に安全な既定のUIにフォールバックしてください。
  • 特定のユーザー操作またはイベントが正常に完了した後に、ゴールをトリガーしてください。
  • 新しい連携ではすべて、コンテキストベースのSDK関数(activateExperimentByContext、getVariationNameByContext、trackGoalByContext)を使用してください。




このドキュメントは、各手順をスムーズに進められるように作成されています。さらにサポートが必要な場合やご不明な点がある場合は、support@zohopagesense.com - までお気軽にお問い合わせください。いつでもサポートいたします。




              Zoho Campaigns Resources

                Zoho WorkDrive Resources




                  • Desk Community Learning Series


                  • Digest


                  • Functions


                  • Meetups


                  • Kbase


                  • Resources


                  • Glossary


                  • Desk Marketplace


                  • MVP Corner


                  • Word of the Day


                  • Ask the Experts









                                  • Related Articles

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

                                    お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。 概要 このガイドでは、React Native Native Bridgeを使用して、PageSense iOS SDKをReact Nativeアプリケーションに連携する方法を説明します。このブリッジにより、React NativeのJavaScriptコードからiOS ...
                                  • PageSense React Native — SDK関数リファレンス

                                    お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。 概要 このドキュメントでは、AndroidとiOSのReact Native連携の両方で共通して使用されるJavaScriptラッパー(PageSenseSDKWrapper.js)について説明します。このラッパーは、React Native Native ...
                                  • PageSense React Native — SDK のカスタマイズ

                                    お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。 概要 PageSense SDKには、初期化時に設定できる設定オプションがあります。これにより、ログ出力の動作や、SDKが更新されたプロジェクト設定を取得する頻度を制御できます。これらのオプションはネイティブモジュールで設定し、AndroidとiOSの両方に適用されます。 ...
                                  • PageSense React Native ブリッジのリリースノート

                                    お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。 概要 このリリースでは、AndroidおよびiOS向けのPageSense React Native ...
                                  • PageSense iOS SDKの初期化

                                    お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。 開始する前に PageSenseClientは、テストの有効化、バリエーションの取得、目標の追跡など、あらゆる操作の中核となるインターフェースです。SDKを初期化するまで、これらの操作は実行できません。 ...

                                  Resources

                                  Videos

                                  Watch comprehensive videos on features and other important topics that will help you master Zoho CRM.



                                  eBooks

                                  Download free eBooks and access a range of topics to get deeper insight on successfully using Zoho CRM.



                                  Webinars

                                  Sign up for our webinars and learn the Zoho CRM basics, from customization to sales force automation and more.



                                  CRM Tips

                                  Make the most of Zoho CRM with these useful tips.