react-native-quicktracking-analytics-module 1.0.3 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/.gradle/7.4/checksums/checksums.lock +0 -0
- package/android/.gradle/7.4/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/7.4/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.4/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/7.4/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/7.4/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.4/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.idea/compiler.xml +6 -0
- package/android/.idea/gradle.xml +19 -0
- package/android/.idea/jarRepositories.xml +35 -0
- package/android/.idea/libraries/Gradle__androidx_activity_activity_1_2_4_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_annotation_annotation_1_3_0.xml +11 -0
- package/android/.idea/libraries/Gradle__androidx_annotation_annotation_experimental_1_1_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_appcompat_appcompat_1_4_1_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_appcompat_appcompat_resources_1_4_1_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_arch_core_core_common_2_1_0.xml +11 -0
- package/android/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_1_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_autofill_autofill_1_1_0_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_collection_collection_1_1_0.xml +11 -0
- package/android/.idea/libraries/Gradle__androidx_core_core_1_7_0_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_cursoradapter_cursoradapter_1_0_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_0_0_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_fragment_fragment_1_3_6_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_interpolator_interpolator_1_0_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_4_0.xml +11 -0
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_3_1_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_4_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_3_1_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_savedstate_2_3_1_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_1_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_swiperefreshlayout_swiperefreshlayout_1_0_0_aar.xml +16 -0
- package/android/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_1_1_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_animated_1_1_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_1_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml +13 -0
- package/android/.idea/libraries/Gradle__com_facebook_fbjni_fbjni_java_only_0_2_2.xml +13 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_drawee_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_fbcore_2_5_0_aar.xml +18 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_fresco_2_5_0_aar.xml +18 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_2_5_0_aar.xml +18 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_base_2_5_0_aar.xml +18 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_native_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_okhttp3_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_memory_type_ashmem_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_memory_type_java_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_memory_type_native_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_nativeimagefilters_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_nativeimagetranscoder_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_fresco_ui_common_2_5_0_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_infer_annotation_infer_annotation_0_18_0.xml +13 -0
- package/android/.idea/libraries/Gradle__com_facebook_react_react_native_0_70_6_debug_aar.xml +14 -0
- package/android/.idea/libraries/Gradle__com_facebook_soloader_annotation_0_10_4.xml +13 -0
- package/android/.idea/libraries/Gradle__com_facebook_soloader_nativeloader_0_10_4.xml +13 -0
- package/android/.idea/libraries/Gradle__com_facebook_soloader_soloader_0_10_4_aar.xml +15 -0
- package/android/.idea/libraries/Gradle__com_facebook_yoga_proguard_annotations_1_19_0.xml +13 -0
- package/android/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_2.xml +13 -0
- package/android/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_4_9_2.xml +13 -0
- package/android/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_urlconnection_4_9_2.xml +13 -0
- package/android/.idea/libraries/Gradle__com_squareup_okio_okio_2_9_0.xml +13 -0
- package/android/.idea/libraries/Gradle__com_umeng_umsdk_qt_px_common_1_4_0_PX_aar.xml +11 -0
- package/android/.idea/libraries/Gradle__javax_inject_javax_inject_1.xml +13 -0
- package/android/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml +13 -0
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_annotations_jvm_1_3_72.xml +13 -0
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_6_10.xml +13 -0
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_common_1_6_10.xml +13 -0
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_jdk7_1_6_10.xml +13 -0
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_jdk8_1_6_10.xml +13 -0
- package/android/.idea/misc.xml +9 -0
- package/android/.idea/modules/android.iml +104 -0
- package/android/.idea/modules.xml +8 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/build.gradle +2 -1
- package/android/local.properties +8 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/QTSDKManager.java +93 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/{QuicktrackingAnalyticsModuleModule.java → QuicktrackingAnalyticsModule.java} +35 -12
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/QuicktrackingAnalyticsModulePackage.java +1 -1
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/property/QTViewProperties.java +48 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/utils/QTLog.java +122 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/utils/RNPropertyManager.java +29 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/utils/RNTouchTargetHelper.java +139 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/utils/RNUtils.java +188 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/utils/RNViewUtils.java +148 -0
- package/ios/NSObject+QTReactNativeSwizzler.h +19 -0
- package/ios/NSObject+QTReactNativeSwizzler.m +38 -0
- package/ios/QTRNUtils.h +21 -0
- package/ios/QTRNUtils.m +48 -0
- package/ios/QTReactNativeRootViewManager.h +41 -0
- package/ios/QTReactNativeRootViewManager.m +100 -0
- package/ios/QTReactNativeViewProperty.h +28 -0
- package/ios/QTReactNativeViewProperty.m +27 -0
- package/ios/QuickTrackingSDKManager.h +25 -0
- package/ios/QuickTrackingSDKManager.m +140 -0
- package/ios/QuicktrackingAnalyticsModule.h +11 -1
- package/ios/QuicktrackingAnalyticsModule.m +47 -4
- package/ios/QuicktrackingAnalyticsModule.xcodeproj/project.pbxproj +42 -0
- package/ios/QuicktrackingAnalyticsModule.xcodeproj/project.xcworkspace/contents.xcworkspacedata +3 -0
- package/ios/QuicktrackingAnalyticsModule.xcodeproj/project.xcworkspace/xcuserdata/yuzhao.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/RCTRootView+QTReactNative.h +23 -0
- package/ios/RCTRootView+QTReactNative.m +56 -0
- package/lib/typescript/index.d.ts +3 -2
- package/package.json +30 -3
- package/react-native-quicktracking-analytics-module.podspec +1 -1
- package/src/hook.js +679 -0
- package/android/.gradle/7.4.2/checksums/checksums.lock +0 -0
- package/android/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.4.2/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.4.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.4.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.4.2/gc.properties +0 -0
- package/android/src/main/java/com/reactnativequicktrackinganalyticsmodule/MainApplication.java +0 -47
- package/ios/.DS_Store +0 -0
package/src/hook.js
ADDED
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
#! node option
|
|
2
|
+
// 系统变量
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const packageJSON = require('../../../package.json');
|
|
6
|
+
const dir = path.resolve(__dirname, '../../');
|
|
7
|
+
|
|
8
|
+
const ChartSet_UTF8 = 'utf8';
|
|
9
|
+
const QTHookTag = 'QUICKTRACKING HOOK';
|
|
10
|
+
const QTBackUpSuffix = '_quicktracking_backup';
|
|
11
|
+
|
|
12
|
+
// 工具函数- add try catch
|
|
13
|
+
function addTryCatch(functionBody) {
|
|
14
|
+
functionBody = functionBody.replace(/this/g, 'thatThis');
|
|
15
|
+
return (
|
|
16
|
+
'(function(thatThis){\n' +
|
|
17
|
+
' try{\n ' +
|
|
18
|
+
functionBody +
|
|
19
|
+
" \n } catch (error) { throw new Error('QUICKTRACKING RN Hook Code 调用异常: ' + error);}\n" +
|
|
20
|
+
'})(this); /* QUICKTRACKING HOOK */'
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 工具函数 - 计算位置
|
|
25
|
+
function lastArgumentName(content, index) {
|
|
26
|
+
--index;
|
|
27
|
+
const lastComma = content.lastIndexOf(',', index);
|
|
28
|
+
const lastParentheses = content.lastIndexOf('(', index);
|
|
29
|
+
const start = Math.max(lastComma, lastParentheses);
|
|
30
|
+
return content.substring(start + 1, index + 1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 自动PV开关
|
|
34
|
+
let enableAutoCLK = false;
|
|
35
|
+
|
|
36
|
+
if (packageJSON && packageJSON['QTSDKConfig']) {
|
|
37
|
+
enableAutoCLK = !!packageJSON['QTSDKConfig']['enableAutoCLK'];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// react native clickable component path
|
|
41
|
+
const RNClickTouchableFilePath =
|
|
42
|
+
dir + '/react-native/Libraries/Components/Touchable/Touchable.js'; //原RNClickFilePath
|
|
43
|
+
const RNClickPressabilityFilePath =
|
|
44
|
+
dir + '/react-native/Libraries/Pressability/Pressability.js';
|
|
45
|
+
const RNClickableFiles = [
|
|
46
|
+
dir +
|
|
47
|
+
'/react-native/Libraries/Renderer/src/renderers/native/ReactNativeFiber.js',
|
|
48
|
+
dir +
|
|
49
|
+
'/react-native/Libraries/Renderer/src/renderers/native/ReactNativeFiber-dev.js',
|
|
50
|
+
dir +
|
|
51
|
+
'/react-native/Libraries/Renderer/src/renderers/native/ReactNativeFiber-prod.js',
|
|
52
|
+
dir +
|
|
53
|
+
'/react-native/Libraries/Renderer/src/renderers/native/ReactNativeFiber-profiling.js',
|
|
54
|
+
dir + '/react-native/Libraries/Renderer/ReactNativeFiber-dev.js',
|
|
55
|
+
dir + '/react-native/Libraries/Renderer/ReactNativeFiber-prod.js',
|
|
56
|
+
dir + '/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js',
|
|
57
|
+
dir + '/react-native/Libraries/Renderer/oss/ReactNativeRenderer-prod.js',
|
|
58
|
+
dir + '/react-native/Libraries/Renderer/ReactNativeStack-dev.js',
|
|
59
|
+
dir + '/react-native/Libraries/Renderer/ReactNativeStack-prod.js',
|
|
60
|
+
dir + '/react-native/Libraries/Renderer/oss/ReactNativeRenderer-profiling.js',
|
|
61
|
+
dir + '/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js',
|
|
62
|
+
dir + '/react-native/Libraries/Renderer/ReactNativeRenderer-prod.js',
|
|
63
|
+
dir +
|
|
64
|
+
'/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js',
|
|
65
|
+
dir +
|
|
66
|
+
'/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js',
|
|
67
|
+
dir +
|
|
68
|
+
'/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js',
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
// react native slider files path
|
|
72
|
+
const RNSliderFiles = [
|
|
73
|
+
dir + '/react-native/Libraries/Components/Slider/Slider.js',
|
|
74
|
+
dir + '/react-native/Libraries/Components/Slider/Slider.js',
|
|
75
|
+
dir + '/@react-native-community/slider/js/Slider.js',
|
|
76
|
+
dir + '/@react-native-community/slider/dist/Slider.js',
|
|
77
|
+
dir + '/@react-native-community/js/Slider.js',
|
|
78
|
+
dir + '/@react-native-community/src/js/Slider.js',
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// react native switch files path
|
|
82
|
+
const RNSwitchFiles = [
|
|
83
|
+
dir + '/react-native/Libraries/Components/Switch/Switch.js',
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
// react native segmentedControl files path
|
|
87
|
+
const RNSegmentedControlFilePath = [
|
|
88
|
+
dir +
|
|
89
|
+
'/react-native/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js',
|
|
90
|
+
dir + '/@react-native-community/segmented-control/js/SegmentedControl.ios.js',
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
// react native gestureButtons files path
|
|
94
|
+
const RNGestureButtonsFilePaths = [
|
|
95
|
+
dir + '/react-native-gesture-handler/GestureButtons.js',
|
|
96
|
+
dir + '/react-native-gesture-handler/src/components/GestureButtons.tsx',
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const QTClickTouchableHookCode = `(function(thatThis) {
|
|
100
|
+
try {
|
|
101
|
+
const ReactNative = require('react-native');
|
|
102
|
+
const qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;
|
|
103
|
+
thatThis.props.onPress && qtModule && qtModule?.onEventAutoCLK(ReactNative.findNodeHandle(thatThis));
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw new Error('QuickTracking RN Hook Code 调用异常: ' + error);
|
|
106
|
+
}
|
|
107
|
+
})(this)
|
|
108
|
+
/* QUICKTRACKING HOOK */ `;
|
|
109
|
+
|
|
110
|
+
const QTClickPressabilityHookCode = `const tag = event.currentTarget && event.currentTarget._nativeTag ? event.currentTarget._nativeTag:event.currentTarget;
|
|
111
|
+
(function(thatThis, e, that){
|
|
112
|
+
if(thatThis){
|
|
113
|
+
try {
|
|
114
|
+
const qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;
|
|
115
|
+
qtModule && qtModule?.onEventAutoCLK(thatThis);
|
|
116
|
+
}catch (error){
|
|
117
|
+
throw new Error('QuickTracking RN Hook Code 调用异常:' + error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
})(tag, event, this); /* QUICKTRACKING HOOK */ `;
|
|
121
|
+
// iOS 全埋点已覆盖
|
|
122
|
+
const QTSliderHookCode =
|
|
123
|
+
'(function(thatThis){\n' +
|
|
124
|
+
' try {\n' +
|
|
125
|
+
" const ReactNative = require('react-native');\n" +
|
|
126
|
+
' const qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;\n' +
|
|
127
|
+
' qtModule && qtModule?.onEventAutoCLK(event.nativeEvent.target);\n' +
|
|
128
|
+
' } catch (error) { \n' +
|
|
129
|
+
" throw new Error('QUICKTRACKING RN Hook Code 调用异常: ' + error);\n" +
|
|
130
|
+
' }\n' +
|
|
131
|
+
'})(this); /* QUICKTRACKING HOOK */';
|
|
132
|
+
// iOS 全埋点覆盖
|
|
133
|
+
const QTSegmentedControlHookCode =
|
|
134
|
+
'if(this.props.onChange != null || this.props.onValueChange != null){\n' +
|
|
135
|
+
'(function(thatThis){\n' +
|
|
136
|
+
' try {\n' +
|
|
137
|
+
" const ReactNative = require('react-native');\n" +
|
|
138
|
+
' const qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;\n' +
|
|
139
|
+
' qtModule && qtModule?.onEventAutoCLK(event.nativeEvent.target);\n' +
|
|
140
|
+
' } catch (error) { \n' +
|
|
141
|
+
" throw new Error('QUICKTRACKING RN Hook Code 调用异常: ' + error);}\n" +
|
|
142
|
+
'})(this); /* QUICKTRACKING HOOK */}';
|
|
143
|
+
// iOS 全埋点已覆盖
|
|
144
|
+
const QTSwitchHookCode = `if(this.props.onChange != null || this.props.onValueChange != null){
|
|
145
|
+
(function(thatThis){
|
|
146
|
+
try {
|
|
147
|
+
const ReactNative = require(react-native);
|
|
148
|
+
const qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;
|
|
149
|
+
qtModule && qtModule?.onEventAutoCLK(ReactNative.findNodeHandle(thatThis));
|
|
150
|
+
} catch (error) {
|
|
151
|
+
throw new Error('QUICKTRACKING RN Hook Code 调用异常: ' + error);
|
|
152
|
+
}
|
|
153
|
+
})(this);
|
|
154
|
+
/* QUICKTRACKING HOOK */}`;
|
|
155
|
+
// iOS 已覆盖
|
|
156
|
+
const QTSwitchHookCode66 = `if(nativeSwitchRef.current && onValueChange){
|
|
157
|
+
(function(thatThis){
|
|
158
|
+
try {
|
|
159
|
+
const ReactNative = require(react-native);
|
|
160
|
+
const qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;
|
|
161
|
+
qtModule && qtModule?.onEventAutoCLK(ReactNative.findNodeHandle(nativeSwitchRef.current));
|
|
162
|
+
} catch (error) {
|
|
163
|
+
throw new Error('QUICKTRACKING RN Hook Code 调用异常:' + error);
|
|
164
|
+
}
|
|
165
|
+
})(this); /* QUICKTRACKING HOOK */}`;
|
|
166
|
+
|
|
167
|
+
// import ReactNative if need
|
|
168
|
+
const QTImportReactNativeHookCode = "import ReactNative from 'react-native';\n";
|
|
169
|
+
|
|
170
|
+
// hook Touchable.js
|
|
171
|
+
function QTTouchableHookRN() {
|
|
172
|
+
if (fs.existsSync(RNClickTouchableFilePath)) {
|
|
173
|
+
// read file content
|
|
174
|
+
let fileContent = fs.readFileSync(RNClickTouchableFilePath, ChartSet_UTF8);
|
|
175
|
+
// already hook, pass
|
|
176
|
+
if (fileContent.indexOf(QTHookTag) > -1) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
console.log(`found Touchable.js: ${RNClickTouchableFilePath}`);
|
|
180
|
+
// get position of the injected code
|
|
181
|
+
const hookIndex = fileContent.indexOf('this.touchableHandlePress(');
|
|
182
|
+
// if method of touchableHandlePress not exist, throw exception
|
|
183
|
+
if (hookIndex === -1) {
|
|
184
|
+
throw "Can't not find touchableHandlePress function";
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const injectedContent = `${fileContent.substring(
|
|
188
|
+
0,
|
|
189
|
+
hookIndex
|
|
190
|
+
)}\n${QTClickTouchableHookCode}\n${fileContent.substring(hookIndex)}`;
|
|
191
|
+
|
|
192
|
+
// backup original Touchable.js file
|
|
193
|
+
fs.renameSync(
|
|
194
|
+
RNClickTouchableFilePath,
|
|
195
|
+
`${RNClickTouchableFilePath}${QTBackUpSuffix}`
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
// rewrite Touchable.js file
|
|
199
|
+
fs.writeFileSync(RNClickTouchableFilePath, injectedContent, ChartSet_UTF8);
|
|
200
|
+
console.log(`modify Touchable.js succeed`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// hook 0.62\0.63 Pressable click
|
|
205
|
+
function QTPressableHookRN() {
|
|
206
|
+
if (fs.existsSync(RNClickPressabilityFilePath)) {
|
|
207
|
+
// read file content
|
|
208
|
+
var fileContent = fs.readFileSync(RNClickPressabilityFilePath, 'utf8');
|
|
209
|
+
// already hook, pass
|
|
210
|
+
if (fileContent.indexOf(QTHookTag) > -1) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
console.log(`found Pressability.js: ${RNClickPressabilityFilePath}`);
|
|
214
|
+
// get position of the injected code
|
|
215
|
+
var scriptStr = 'onPress(event);';
|
|
216
|
+
var hookIndex = fileContent.lastIndexOf(scriptStr);
|
|
217
|
+
// if method of onPress not exist, throw exception
|
|
218
|
+
|
|
219
|
+
if (hookIndex === -1) {
|
|
220
|
+
throw "Can't not find onPress(event); code";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
var hookedContent = `${fileContent.substring(
|
|
224
|
+
0,
|
|
225
|
+
hookIndex
|
|
226
|
+
)}\n${QTClickPressabilityHookCode}\n${fileContent.substring(hookIndex)}`;
|
|
227
|
+
// backup original Pressability.js file
|
|
228
|
+
if (fileContent.indexOf(`${QTImportReactNativeHookCode}`) === -1) {
|
|
229
|
+
hookedContent = QTImportReactNativeHookCode + hookedContent;
|
|
230
|
+
}
|
|
231
|
+
fs.renameSync(
|
|
232
|
+
RNClickPressabilityFilePath,
|
|
233
|
+
`${RNClickPressabilityFilePath}${QTBackUpSuffix}`
|
|
234
|
+
);
|
|
235
|
+
// rewrite Pressability.js file
|
|
236
|
+
fs.writeFileSync(RNClickPressabilityFilePath, hookedContent, ChartSet_UTF8);
|
|
237
|
+
console.log(`modify Pressability.js succeed`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// hook slider
|
|
242
|
+
function QTHookSliderRN(reset = false) {
|
|
243
|
+
RNSliderFiles.forEach(function (onefile) {
|
|
244
|
+
if (fs.existsSync(onefile)) {
|
|
245
|
+
// 读取文件内容
|
|
246
|
+
const fileContent = fs.readFileSync(onefile, ChartSet_UTF8);
|
|
247
|
+
if (reset) {
|
|
248
|
+
// 未被 hook 过代码,不需要处理
|
|
249
|
+
if (fileContent.indexOf(QTHookTag) === -1) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// 检查备份文件是否存在
|
|
253
|
+
const backFilePath = `${onefile}${QTBackUpSuffix}`;
|
|
254
|
+
if (!fs.existsSync(backFilePath)) {
|
|
255
|
+
throw `File: ${backFilePath} not found, Please rm -rf node_modules and npm install again`;
|
|
256
|
+
}
|
|
257
|
+
// 将备份文件重命名恢复 + 自动覆盖被 hook 过的同名文件
|
|
258
|
+
fs.renameSync(backFilePath, onefile);
|
|
259
|
+
console.log(`found and reset Slider.js: ${onefile}`);
|
|
260
|
+
} else {
|
|
261
|
+
// 已经 hook 过了,不需要再次 hook
|
|
262
|
+
if (fileContent.indexOf(QTHookTag) > -1) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
console.log(`found Slider.js: ${onefile}`);
|
|
266
|
+
// 获取 hook 的代码插入的位置
|
|
267
|
+
const scriptStr = 'onSlidingComplete(event.nativeEvent.value);';
|
|
268
|
+
const hookIndex = fileContent.indexOf(scriptStr);
|
|
269
|
+
// 判断文件是否异常,不存在 touchableHandlePress 方法,导致无法 hook 点击事件
|
|
270
|
+
if (hookIndex === -1) {
|
|
271
|
+
throw "Can't not find onSlidingComplete function";
|
|
272
|
+
}
|
|
273
|
+
// 插入 hook 代码
|
|
274
|
+
const hookedContent = `${fileContent.substring(
|
|
275
|
+
0,
|
|
276
|
+
hookIndex + scriptStr.length
|
|
277
|
+
)}\n${QTSliderHookCode}\n${fileContent.substring(
|
|
278
|
+
hookIndex + scriptStr.length
|
|
279
|
+
)}`;
|
|
280
|
+
// 备份源文件
|
|
281
|
+
fs.renameSync(onefile, `${onefile}${QTBackUpSuffix}`);
|
|
282
|
+
// 重写文件
|
|
283
|
+
fs.writeFileSync(onefile, hookedContent, ChartSet_UTF8);
|
|
284
|
+
console.log(`modify Slider.js succeed`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// hook switch
|
|
290
|
+
function QTHookSwitchRN(reset = false) {
|
|
291
|
+
RNSwitchFiles.forEach(function (onefile) {
|
|
292
|
+
if (fs.existsSync(onefile)) {
|
|
293
|
+
// 读取文件内容
|
|
294
|
+
const fileContent = fs.readFileSync(onefile, 'utf8');
|
|
295
|
+
if (reset) {
|
|
296
|
+
// 未被 hook 过代码,不需要处理
|
|
297
|
+
if (fileContent.indexOf(`${QTHookTag}`) === -1) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// 检查备份文件是否存在
|
|
301
|
+
const backFilePath = `${onefile}${QTBackUpSuffix}`;
|
|
302
|
+
if (!fs.existsSync(backFilePath)) {
|
|
303
|
+
throw `File: ${backFilePath} not found, Please rm -rf node_modules and npm install again`;
|
|
304
|
+
}
|
|
305
|
+
// 将备份文件重命名恢复 + 自动覆盖被 hook 过的同名文件
|
|
306
|
+
fs.renameSync(backFilePath, onefile);
|
|
307
|
+
console.log(`found and reset Switch.js: ${onefile}`);
|
|
308
|
+
} else {
|
|
309
|
+
// 已经 hook 过了,不需要再次 hook
|
|
310
|
+
if (fileContent.indexOf(`${QTHookTag}`) > -1) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
console.log(`found Switch.js: ${onefile}`);
|
|
314
|
+
// 特殊情况的单独插入
|
|
315
|
+
// if (this.props.onValueChange != null) {
|
|
316
|
+
let scriptStr = 'if (this.props.onValueChange != null) {';
|
|
317
|
+
let hookIndex = fileContent.indexOf(scriptStr);
|
|
318
|
+
if (hookIndex > -1) {
|
|
319
|
+
// 插入 hook 代码
|
|
320
|
+
const hookedContent = `${fileContent.substring(
|
|
321
|
+
0,
|
|
322
|
+
hookIndex
|
|
323
|
+
)}\n${QTSwitchHookCode}\n${fileContent.substring(hookIndex)}`;
|
|
324
|
+
// 备份源文件
|
|
325
|
+
fs.renameSync(onefile, `${onefile}${QTBackUpSuffix}`);
|
|
326
|
+
// 重写文件
|
|
327
|
+
fs.writeFileSync(onefile, hookedContent, 'utf8');
|
|
328
|
+
console.log(`modify Switch.js: ${onefile}`);
|
|
329
|
+
} else {
|
|
330
|
+
// 获取 hook 的代码插入的位置
|
|
331
|
+
scriptStr = 'this.props.onValueChange(event.nativeEvent.value);';
|
|
332
|
+
hookIndex = fileContent.indexOf(scriptStr);
|
|
333
|
+
let hookcontent;
|
|
334
|
+
if (hookIndex === -1) {
|
|
335
|
+
scriptStr = 'onValueChange?.(event.nativeEvent.value);';
|
|
336
|
+
hookIndex = fileContent.indexOf(scriptStr);
|
|
337
|
+
hookcontent = QTSwitchHookCode66;
|
|
338
|
+
} else {
|
|
339
|
+
hookcontent = QTSwitchHookCode;
|
|
340
|
+
}
|
|
341
|
+
// 判断文件是否异常,不存在 touchableHandlePress 方法,导致无法 hook 点击事件
|
|
342
|
+
if (hookIndex === -1) {
|
|
343
|
+
throw "Can't not find onValueChange function";
|
|
344
|
+
}
|
|
345
|
+
// 插入 hook 代码
|
|
346
|
+
const hookedContent = `${fileContent.substring(
|
|
347
|
+
0,
|
|
348
|
+
hookIndex + scriptStr.length
|
|
349
|
+
)}\n${hookcontent}\n${fileContent.substring(
|
|
350
|
+
hookIndex + scriptStr.length
|
|
351
|
+
)}`;
|
|
352
|
+
// 备份源文件
|
|
353
|
+
fs.renameSync(onefile, `${onefile}${QTBackUpSuffix}`);
|
|
354
|
+
// 重写文件
|
|
355
|
+
fs.writeFileSync(onefile, hookedContent, 'utf8');
|
|
356
|
+
console.log(`modify Switch.js succeed`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
// hook SegmentedControl
|
|
363
|
+
function QTHookSegmentedControlRN(reset = false) {
|
|
364
|
+
RNSegmentedControlFilePath.forEach(function (onefile) {
|
|
365
|
+
if (fs.existsSync(onefile)) {
|
|
366
|
+
// 读取文件内容
|
|
367
|
+
const fileContent = fs.readFileSync(onefile, ChartSet_UTF8);
|
|
368
|
+
if (reset) {
|
|
369
|
+
// 未被 hook 过代码,不需要处理
|
|
370
|
+
if (fileContent.indexOf(`${QTHookTag}`) === -1) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
// 检查备份文件是否存在
|
|
374
|
+
const backFilePath = `${onefile}${QTBackUpSuffix}`;
|
|
375
|
+
if (!fs.existsSync(backFilePath)) {
|
|
376
|
+
throw `File: ${backFilePath} not found, Please rm -rf node_modules and npm install again`;
|
|
377
|
+
}
|
|
378
|
+
// 将备份文件重命名恢复 + 自动覆盖被 hook 过的同名文件
|
|
379
|
+
fs.renameSync(backFilePath, onefile);
|
|
380
|
+
console.log(`found and reset SegmentedControl.js: ${onefile}`);
|
|
381
|
+
} else {
|
|
382
|
+
// 已经 hook 过了,不需要再次 hook
|
|
383
|
+
if (fileContent.indexOf(`${QTHookTag}`) > -1) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
console.log(`found SegmentedControl.js: ${onefile}`);
|
|
387
|
+
// 获取 hook 的代码插入的位置
|
|
388
|
+
const scriptStr = 'this.props.onValueChange(event.nativeEvent.value);';
|
|
389
|
+
const hookIndex = fileContent.indexOf(scriptStr);
|
|
390
|
+
// 判断文件是否异常,不存在 touchableHandlePress 方法,导致无法 hook 点击事件
|
|
391
|
+
if (hookIndex === -1) {
|
|
392
|
+
throw "Can't not find onValueChange function";
|
|
393
|
+
}
|
|
394
|
+
// 插入 hook 代码
|
|
395
|
+
const hookedContent = `${fileContent.substring(
|
|
396
|
+
0,
|
|
397
|
+
hookIndex + scriptStr.length
|
|
398
|
+
)}\n${QTSegmentedControlHookCode}\n${fileContent.substring(
|
|
399
|
+
hookIndex + scriptStr.length
|
|
400
|
+
)}`;
|
|
401
|
+
// 备份 Touchable.js 源文件
|
|
402
|
+
fs.renameSync(onefile, `${onefile}${QTBackUpSuffix}`);
|
|
403
|
+
// 重写 Touchable.js 文件
|
|
404
|
+
fs.writeFileSync(onefile, hookedContent, ChartSet_UTF8);
|
|
405
|
+
console.log(`modify SegmentedControl.js succeed`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// hook GestureButtons
|
|
412
|
+
function QTHookGestureButtonsRN(reset = false) {
|
|
413
|
+
RNGestureButtonsFilePaths.forEach(function (onefile) {
|
|
414
|
+
if (fs.existsSync(onefile)) {
|
|
415
|
+
// 读取文件内容
|
|
416
|
+
const fileContent = fs.readFileSync(onefile, ChartSet_UTF8);
|
|
417
|
+
if (reset) {
|
|
418
|
+
// 未被 hook 过代码,不需要处理
|
|
419
|
+
if (fileContent.indexOf(`${QTHookTag}`) === -1) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
// 检查备份文件是否存在
|
|
423
|
+
const backFilePath = `${onefile}${QTBackUpSuffix}`;
|
|
424
|
+
if (!fs.existsSync(backFilePath)) {
|
|
425
|
+
throw `File: ${backFilePath} not found, Please rm -rf node_modules and npm install again`;
|
|
426
|
+
}
|
|
427
|
+
// 将备份文件重命名恢复 + 自动覆盖被 hook 过的同名文件
|
|
428
|
+
fs.renameSync(backFilePath, onefile);
|
|
429
|
+
console.log(`found and reset GestureButtons: ${onefile}`);
|
|
430
|
+
} else {
|
|
431
|
+
// 已经 hook 过了,不需要再次 hook
|
|
432
|
+
if (fileContent.indexOf(`${QTHookTag}`) > -1) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
console.log(`found GestureButtons: ${onefile}`);
|
|
436
|
+
// 获取 hook 的代码插入的位置
|
|
437
|
+
const scriptStr = 'this.props.onPress(active);';
|
|
438
|
+
const hookIndex = fileContent.indexOf(scriptStr);
|
|
439
|
+
// 判断文件是否异常,不存在 this.props.onPress(active); 导致无法 hook 点击事件
|
|
440
|
+
if (hookIndex === -1) {
|
|
441
|
+
throw "Can't not find this.props.onPress(active); ";
|
|
442
|
+
}
|
|
443
|
+
// 插入 hook 代码
|
|
444
|
+
const hookedContent = `${fileContent.substring(
|
|
445
|
+
0,
|
|
446
|
+
hookIndex + scriptStr.length
|
|
447
|
+
)}\n${QTClickTouchableHookCode}\n${fileContent.substring(
|
|
448
|
+
hookIndex + scriptStr.length
|
|
449
|
+
)}`;
|
|
450
|
+
// 备份目标源文件
|
|
451
|
+
fs.renameSync(onefile, `${onefile}${QTBackUpSuffix}`);
|
|
452
|
+
// 重写修改后的文件
|
|
453
|
+
fs.writeFileSync(onefile, hookedContent, ChartSet_UTF8);
|
|
454
|
+
console.log(`modify GestureButtons succeed`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// hook clickable
|
|
461
|
+
function QTHookClickableRN(reset = false) {
|
|
462
|
+
RNClickableFiles.forEach(function (onefile) {
|
|
463
|
+
if (fs.existsSync(onefile)) {
|
|
464
|
+
if (reset) {
|
|
465
|
+
// 读取文件内容
|
|
466
|
+
const fileContent = fs.readFileSync(onefile, ChartSet_UTF8);
|
|
467
|
+
// 未被 hook 过代码,不需要处理
|
|
468
|
+
if (fileContent.indexOf(`${QTHookTag}`) === -1) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
// 检查备份文件是否存在
|
|
472
|
+
const backFilePath = `${onefile}${QTBackUpSuffix}`;
|
|
473
|
+
if (!fs.existsSync(backFilePath)) {
|
|
474
|
+
throw `File: ${backFilePath} not found, Please rm -rf node_modules and npm install again`;
|
|
475
|
+
}
|
|
476
|
+
// 将备份文件重命名恢复 + 自动覆盖被 hook 过的同名文件
|
|
477
|
+
fs.renameSync(backFilePath, onefile);
|
|
478
|
+
console.log(`found and reset clickable: ${onefile}`);
|
|
479
|
+
} else {
|
|
480
|
+
// 读取文件内容
|
|
481
|
+
const content = fs.readFileSync(onefile, 'utf8');
|
|
482
|
+
// 已经 hook 过了,不需要再次 hook
|
|
483
|
+
if (content.indexOf(`${QTHookTag}`) > -1) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
console.log(`found clickable.js: ${onefile}`);
|
|
487
|
+
// 获取 hook 的代码插入的位置
|
|
488
|
+
let objRe =
|
|
489
|
+
/ReactNativePrivateInterface\.UIManager\.createView\([\s\S]{1,60}\.uiViewClassName,[\s\S]*?\)[,;]/;
|
|
490
|
+
let match = objRe.exec(content);
|
|
491
|
+
if (!match) {
|
|
492
|
+
objRe =
|
|
493
|
+
/UIManager\.createView\([\s\S]{1,60}\.uiViewClassName,[\s\S]*?\)[,;]/;
|
|
494
|
+
match = objRe.exec(content);
|
|
495
|
+
}
|
|
496
|
+
if (!match) {
|
|
497
|
+
throw "can't inject clickable js";
|
|
498
|
+
}
|
|
499
|
+
const lastParentheses = content.lastIndexOf(')', match.index);
|
|
500
|
+
const nextCommaIndex = content.indexOf(',', match.index);
|
|
501
|
+
if (nextCommaIndex === -1)
|
|
502
|
+
throw "can't inject clickable js, and nextCommaIndex is -1";
|
|
503
|
+
const tagName = lastArgumentName(content, nextCommaIndex).trim();
|
|
504
|
+
const functionBody = `
|
|
505
|
+
var qtElement;
|
|
506
|
+
if(typeof internalInstanceHandle !== 'undefined') {
|
|
507
|
+
qtElement = internalInstanceHandle;
|
|
508
|
+
} else if(typeof workInProgress !== 'undefined') {
|
|
509
|
+
qtElement = workInProgress;
|
|
510
|
+
} else if(typeof thatThis._currentElement !== 'undefined') {
|
|
511
|
+
qtElement = thatThis._currentElement;
|
|
512
|
+
}
|
|
513
|
+
var eachProgress = function (workInProgress) {
|
|
514
|
+
if(workInProgress == null){
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
var props;
|
|
518
|
+
if(workInProgress.memoizedProps) {
|
|
519
|
+
props = workInProgress.memoizedProps;
|
|
520
|
+
} else if(workInProgress.props){
|
|
521
|
+
props = workInProgress.props;
|
|
522
|
+
}
|
|
523
|
+
if(props && props.qtParams) {
|
|
524
|
+
return props.qtParams;
|
|
525
|
+
} else {
|
|
526
|
+
if(!props ||
|
|
527
|
+
!workInProgress.type ||
|
|
528
|
+
workInProgress.type.displayName === 'TouchableOpacity' ||
|
|
529
|
+
workInProgress.type.displayName === 'TouchableHighlight' ||
|
|
530
|
+
workInProgress.type.displayName === 'TouchableWithoutFeedback'||
|
|
531
|
+
workInProgress.type.displayName === 'TouchableNativeFeedback'||
|
|
532
|
+
workInProgress.type.displayName === 'Pressable'||
|
|
533
|
+
workInProgress.type.name === 'TouchableOpacity' ||
|
|
534
|
+
workInProgress.type.name === 'TouchableHighlight' ||
|
|
535
|
+
workInProgress.type.name === 'TouchableNativeFeedback'||
|
|
536
|
+
workInProgress.type.name === 'TouchableWithoutFeedback'||
|
|
537
|
+
workInProgress.type.displayName === undefined||
|
|
538
|
+
workInProgress.type.name === undefined ||
|
|
539
|
+
!props.onPress
|
|
540
|
+
) {
|
|
541
|
+
if(workInProgress.return) {
|
|
542
|
+
return eachProgress(workInProgress.return);
|
|
543
|
+
} else {
|
|
544
|
+
if(workInProgress._owner && workInProgress._owner._currentElement) {
|
|
545
|
+
return eachProgress(workInProgress._owner._currentElement);
|
|
546
|
+
} else {
|
|
547
|
+
return eachProgress(workInProgress._owner);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
var elementProps;
|
|
554
|
+
if(qtElement && qtElement.memoizedProps) {
|
|
555
|
+
elementProps = qtElement.memoizedProps;
|
|
556
|
+
} else if(qtElement && qtElement.props) {
|
|
557
|
+
elementProps = qtElement.props;
|
|
558
|
+
}
|
|
559
|
+
if(elementProps) {
|
|
560
|
+
// iOS 兼容 SegmentedControl 逻辑
|
|
561
|
+
var isSegmentedControl = (
|
|
562
|
+
qtElement && (
|
|
563
|
+
qtElement.type === 'RNCSegmentedControl' ||
|
|
564
|
+
qtElement.type === 'RCTSegmentedControl' ||
|
|
565
|
+
qtElement.type.name === 'RNCSegmentedControl' ||
|
|
566
|
+
qtElement.type.name === 'RCTSegmentedControl' ||
|
|
567
|
+
qtElement.type.displayName === 'RNCSegmentedControl' ||
|
|
568
|
+
qtElement.type.displayName === 'RCTSegmentedControl'
|
|
569
|
+
)
|
|
570
|
+
);
|
|
571
|
+
if(elementProps.onStartShouldSetResponder || isSegmentedControl) {
|
|
572
|
+
var qtProps = eachProgress(qtElement);
|
|
573
|
+
var ReactNative = require('react-native');
|
|
574
|
+
|
|
575
|
+
var qtModule = ReactNative.NativeModules.QuicktrackingAnalyticsModule;
|
|
576
|
+
if(qtModule && qtModule.saveRootViewProperties) {
|
|
577
|
+
var qtRootTag;
|
|
578
|
+
if(typeof nativeTopRootTag !== 'undefined') {
|
|
579
|
+
qtRootTag = nativeTopRootTag;
|
|
580
|
+
} else if(typeof rootContainerInstance !== 'undefined') {
|
|
581
|
+
qtRootTag = rootContainerInstance;
|
|
582
|
+
} else if(typeof renderExpirationTime !== 'undefined') {
|
|
583
|
+
qtRootTag = renderExpirationTime;
|
|
584
|
+
} else if(typeof renderLanes !== 'undefined') {
|
|
585
|
+
qtRootTag = renderLanes;
|
|
586
|
+
}
|
|
587
|
+
if (qtRootTag && (typeof qtRootTag === 'number')) {
|
|
588
|
+
qtModule.saveRootViewProperties(${tagName}, true , qtProps, qtRootTag);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
qtModule && qtModule.saveViewProperties && qtModule.saveViewProperties(${tagName}, true, qtProps);
|
|
593
|
+
}
|
|
594
|
+
}`;
|
|
595
|
+
const call = addTryCatch(functionBody);
|
|
596
|
+
const lastReturn = content.lastIndexOf('return', match.index);
|
|
597
|
+
let splitIndex = match.index;
|
|
598
|
+
if (lastReturn > lastParentheses) {
|
|
599
|
+
splitIndex = lastReturn;
|
|
600
|
+
}
|
|
601
|
+
const hookedContent = `${content.substring(
|
|
602
|
+
0,
|
|
603
|
+
splitIndex
|
|
604
|
+
)}\n${call}\n${content.substring(splitIndex)}`;
|
|
605
|
+
|
|
606
|
+
// 备份源文件
|
|
607
|
+
fs.renameSync(onefile, `${onefile}${QTBackUpSuffix}`);
|
|
608
|
+
// 重写文件
|
|
609
|
+
fs.writeFileSync(onefile, hookedContent, ChartSet_UTF8);
|
|
610
|
+
console.log(`modify clickable.js succeed`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function resetQTHookCodeRN(resetFilePath) {
|
|
617
|
+
// 判断需要被恢复的文件是否存在
|
|
618
|
+
if (!fs.existsSync(resetFilePath)) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
const fileContent = fs.readFileSync(resetFilePath, 'utf8');
|
|
622
|
+
// 未被 hook 过代码,不需要处理
|
|
623
|
+
if (fileContent.indexOf(`${QTHookTag}`) === -1) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
// 检查备份文件是否存在
|
|
627
|
+
const backFilePath = `${resetFilePath}${QTBackUpSuffix}`;
|
|
628
|
+
if (!fs.existsSync(backFilePath)) {
|
|
629
|
+
throw `File: ${backFilePath} not found, Please rm -rf node_modules and npm install again`;
|
|
630
|
+
}
|
|
631
|
+
// 将备份文件重命名恢复 + 自动覆盖被 hook 过的同名 Touchable.js 文件
|
|
632
|
+
fs.renameSync(backFilePath, resetFilePath);
|
|
633
|
+
console.log(`found and reset file: ${resetFilePath}`);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// hook all auto click event entry
|
|
637
|
+
function QTHookClickEventRN() {
|
|
638
|
+
QTTouchableHookRN(RNClickTouchableFilePath);
|
|
639
|
+
QTHookClickableRN();
|
|
640
|
+
QTHookSliderRN();
|
|
641
|
+
QTHookSegmentedControlRN();
|
|
642
|
+
QTHookGestureButtonsRN();
|
|
643
|
+
QTPressableHookRN();
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function resetAllQTHookFiles() {
|
|
647
|
+
resetQTHookCodeRN(RNClickTouchableFilePath);
|
|
648
|
+
|
|
649
|
+
QTHookClickableRN(true);
|
|
650
|
+
|
|
651
|
+
QTHookSliderRN(true);
|
|
652
|
+
QTHookSwitchRN(true);
|
|
653
|
+
QTHookSegmentedControlRN(true);
|
|
654
|
+
QTHookGestureButtonsRN(true);
|
|
655
|
+
|
|
656
|
+
resetQTHookCodeRN(RNClickPressabilityFilePath);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// hook all files entry
|
|
660
|
+
function QTHookAllFiles() {
|
|
661
|
+
if (!enableAutoCLK) {
|
|
662
|
+
console.log('customers ignore auto click event');
|
|
663
|
+
} else {
|
|
664
|
+
QTHookClickEventRN();
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// 命令行
|
|
669
|
+
switch (process.argv[2]) {
|
|
670
|
+
case '-run':
|
|
671
|
+
resetAllQTHookFiles();
|
|
672
|
+
QTHookAllFiles();
|
|
673
|
+
break;
|
|
674
|
+
case '-reset':
|
|
675
|
+
resetAllQTHookFiles();
|
|
676
|
+
break;
|
|
677
|
+
default:
|
|
678
|
+
console.log('can not find this options: ' + process.argv[2]);
|
|
679
|
+
}
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
File without changes
|