一、前言
React Native 是由 Facebook 推出的移动应用开发框架,可以用来开发 iOS、Android、Web 等跨平台应用程序,官网为: facebook.github.io/react-nativ… React Native 和传统的 Hybrid 应用最大的区别就是它抛开了 WebView 控件。React Native 产出的并不是 “网页应用”、“HTML5 应用” 或者 “混合应用”,而是一个真正的移动应用,从使用感受上和用 Objective-C 或 Java 编写的应用相比几乎是没有区别的。React Native 所使用的基础 UI 组件和原生应用完全一致。我们要做的就是把这些基础组件使用 JavaScript 和 React 的方式组合起来。React Native 是一个非常优秀的跨平台框架。
React Native 可以通过自定义 Module [1] 的方式实现 JavaScript 调用 Native 接口,神策分析的 React Native Module [2]在 v2.0 版本使用新方案实现了 React Native 全埋点功能。本文主要介绍神策分析 React Native Module 是如何实现 $AppClick(全埋点的点击事件) 功能的,内容以 iOS 项目为例。
二、原理分析
2.1触发点击
在 React Native 中没有专门的按钮组件,为了让视图能够响应用户的点击事件,我们需要借助 Touchable 系列组件来包装我们的视图。
2.1.1 Touchable 系列组件
Touchable 系列组件中的四个组件都可以用来包装视图,从而响应用户的点击事件:
- TouchableHighlight:在用户手指按下时背景会有变暗的效果;
- TouchableNativeFeedback:在 Android 上可以使用 TouchableNativeFeedback,它会在用户手指按下时形成类似水波纹的视觉效果。注意,此组件只支持 Android;
- TouchableOpacity:会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色;
- TouchableWithoutFeedback:响应用户的点击事件,如果你想在处理点击事件的同时不显示任何视觉反馈,使用它是个不错的选择。
以上组件中前三者都是在 TouchableWithoutFeedback 的基础上做了一些扩展,我们从源码中可以看出:
TouchableHighlight
TouchableNativeFeedback
TouchableOpacity
因为 TouchableWithoutFeedback 有其他组件的共同属性,所以我们只需要来了解下 TouchableWithoutFeedback 是如何实现点击功能的。
2.1.2 Touchable 功能介绍
React Native 的响应系统用起来可能比较复杂,因此官方提供了一个抽象的 Touchable 实现,用来做 “可触控” 的组件。Touchable 系列组件相关文件都在 node_modules/react-native/Libraries/Components/Touchable 文件夹中。在 Touchable 文件夹下也提供了 Touchable.js 文件,点击功能的实现都是在此文件中。 React Native 对 Touchable.js 的描述如下:
从描述中可以看出,Touchable 会帮助开发者处理触摸交互,当有其他响应者响应了触摸交互时,Touchable 也会及时通知控件向用户提供反馈。
2.1.3 Touchable 状态变化
React Native 控件的触摸操作是会发生变化的,为了监听控件触摸状态的变化,React Native 在 Touchable 中声明了 State 和 Signal 类型来描述用户的触摸行为。
State
Signal
交互流程如图 2-1 所示:
图 2-1 交互流程图(参考:React Native 源码 [3])
从图 2-1 中可以看出,当 State 为 RESPONDER_ACTIVE_PRESS_IN 并且 Signal 为 RESPONDER_RELEASE 时,表示用户正在点击控件。因此,我们可以在这里触发控件的点击事件采集。
_performSideEffectsForTransition 函数中已有此逻辑的判断,我们可以在这里添加打印信息来验证方案的可行性:
在项目入口文件 App.js 中添加 Button 按钮并运行项目,点击 Button 按钮可以看到终端控制台打印内容 “这里是按钮点击”,如图 2-2 所示:
图 2-2 控制台打印信息
至此,我们就找到了触发 $AppClick 事件的时机。
2.2 创建视图
上一节中我们已经找到了触发 $AppClick 事件的时机。但是,还存在一个问题:在 React Native 中是无法直接获取到触发点击事件对应的 View 对象。针对这一问题,我们可以通过 reactTag 来解决。
2.2.1 reactTag
在 React Native 项目中会给每个 View 分配一个唯一的 id(reactTag)。reactTag 是一个递增的整型数字,我们可以通过 reactTag 来找到每一个 View 对象。 RCTRootView 作为整个 React Native 项目的入口,初始化时会默认将 1 分配给 RCTRootView 作为 reactTag,即 RootTag 。
我们下面来看下 reactTag 的生成规则:
从上面的代码片段中可以看出,tag 以 +2 的方式递增,当 tag % 10 === 1 时会再做一次累加。因此,tag % 10 === 1 只会出现一次,即 RootTag。
2.2.2 创建视图
在 React Native 中所有的 View 都是通过 RCTUIManager 类来进行创建并管理的。RCTUIManager 类提供了如下方法来创建 View 对象:
下面我们需要找到此方法是在哪里调用的,这样就可以知道在 JavaScript 端创建 View 的时机。经过在 react-native 源码中查找,定位到 /node_modules/react-native/Renderer/implementations/ReactNativeRenderer-dev.js 中有如下代码片段:
可以看出,这里就是 JavaScript 端创建 View 的代码位置。我们可以在这里添加 Hook 代码将 View 的 reactTag 保存起来。
2.2.3 方案简述
根据前面两节的内容可知,我们可以在 UIManager 创建视图时将可点击视图的 reactTag 保存起来,当控件触发点击时通过对比 reactTag 判断当前点击的视图是否为可点击,并通过 reactTag 找到对应的 View 对象触发 $AppClick 点击事件。
三、准备工作
3.1创建项目
在实现 React Native 点击事件采集方案之前,我们首先创建一个演示项目。详细的安装步骤可以参考官网 environment-setup [4]部分,现在使用下面的命令创建一个 React Native 项目。
注意:0.62.x 及以上版本针对控件点击功能源码有部分改动,我们已在神策分析 React Native Module 后续版本中进行了兼容。这里为了演示效果,我们仍以 v0.61.5 版本来进行后续功能的说明。 通过以上命令我们已经创建了一个 AwesomeProject 的 React Native 项目,并可以成功运行项目。项目如图 3-1 所示:
图 3-1 React Native 项目截图
3.2 集成神策分析
- 在项目目录下执行 "cd ios" 命令后再执行 "vim Podfile" 命令编辑 Podfile 文件。将" pod 'SensorsAnalyticsSDK' " 添加在文件中后保存,并执行 "pod install" 命令集成神策分析 SDK。Podfile 文件内容如下:
- 将AwesomeProject.xcworkspace 打开(在 “ios 文件夹” 下),并在 AppDelegate 中初始化神策分析 SDK:
完成初始化 SDK 后运行项目,可以看到控制台会打印出 $AppStart 事件。
3.3 创建 Module
集成神策分析 SDK 后我们还需要创建一个 React Native Module 用来将 Native 触发 $AppClick 的接口提供给 JavaScript 端调用。
- 打开 Xcode 并选择 File → New → Project...,输入静态库名称 SensorsAnalyticsModule。如图 3-2 所示:
图 3-2 创建 Module
- 在静态库项目文件夹下添加 SensorsAnalyticsModule.podspec 文件,文件内容如下:
- 将创建的 SensorsAnalyticsModule 工程文件夹移动到演示项目根目录下,并在演示项目 “ios 文件夹” 下的 Podfile 文件中,添加 SensorsAnalyticsModule 引用:
运行项目后可以正常工作,至此准备工作已完成。
四、代码实现
通过前面的介绍,我们已经知道了实现 $AppClick 事件功能的关键步骤,下面来详细说明下代码的实现。
4.1 Module
- 在 SensorsAnalyticsModule.h 中添加 RCTBridgeModule 引用及实现协议内容:
- 在 SensorsAnalyticsModule.m 中新增 reactTags 集合属性来保存可点击视图的 reactTag 信息:
- 在 SensorsAnalyticsModule.m 中添加 Module 声明,并添加 + sharedInstance 方法:
- 新增 saveReactTag:clickable: 方法用来保存可点击视图的 reactTag,并将此方法通过 RCT_EXPORT_METHOD 提供给 JavaScript 端调用:
- 通过 reactTag 找到对应视图:
- 新增 trackViewClick: 方法用来触发 AppClick事件。在trackViewClick:方法中通过reactTag找到对应的视图后触发AppClick 事件:
4.2 手动插入代码
1.在 /node_modules/react-native/Renderer/implementations/ReactNativeRenderer-dev.js 的“ReactNativePrivateInterface.UIManager.createView” 代码前插入 Hook 代码如下:
- 在 node_modules/react-native/Libraries/Components/Touchable/Touchable.js 的 “this.touchableHandlePress(e);” 代码前插入 Hook 代码如下:
运行项目并点击 Button ,项目的控制台中已打印出 Button 的 AppClick事件信息。至此,完成了ReactNative全埋点的AppClick 事件采集功能。如图 4-1 所示:
图 4-1 触发的点击事件信息
4.3 自动插入代码
在上一节中,我们是手动插入了 React Native JavaScript 端的 Hook 代码,这种方案并不利于后期代码的维护以及不同 React Native 版本的兼容。因此,在这里需要新增一个 Hook 文件用来实现源码的自动插入功能。
- 新建 Hook.js 文件放在演示项目的根目录下,并添加系统变量和文件位置:
- 添加后续需要用到的工具类方法:
- 添加 Hook Touchable.js 文件的代码片段:
- 添加 Hook 获取 reactTag 信息的代码片段:
- 添加代码还原功能:
- 定义执行命令:
- 删除手动插入的代码片段,在演示项目的根目录执行 "node Hook.js -run",Hook 成功后会打印出插入代码的文件路径。运行项目测试 Button 点击,可以在控制台正常打印信息。如图 4-2 所示:
图 4-2 触发的点击事件
五、总结
总的来说,神策分析 React Native Module 在 v2.0 版本使用的方案是 Hook React Native JavaScript 端的源码,实现 $AppClick 事件的采集功能。
使用这种方案实现有如下优点:
- 点击控件采集到的信息更准确(主要是 $screen_name 的准确性,这部分内容会在后续的 React Native 页面浏览全埋点方案中重点讲解);
- 和 Native SDK 解耦,不再需要 Native SDK 配合 React Native Module 版本更新。
但是这种方案也存在如下缺点:
- 对 React Native JavaScript 端源码进行改动,一定程度上会造成 React Native 代码的不稳定性。
在这里我们为了保证数据的准确性仍然使用此方案,并且在 Hook 代码中做了一定的代码保护,尽最大的努力减少数据埋点带来的风险性。
参考文献: [1]reactnative.dev/docs/native… [2]manual.sensorsdata.cn/sa/latest/t… [3]github.com/facebook/re… [4]reactnative.dev/docs/enviro…
文章来源:神策技术社区
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!