From 20754adc64542f241b9294d73f5bfbd08f7cbe57 Mon Sep 17 00:00:00 2001 From: arnonchen <52275454+Cyunong@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:41:00 +0800 Subject: [PATCH 01/10] fix(devtools): fix network debug information for ios in chrome devtool (#4112) --- framework/ios/base/executors/HippyJSExecutor.mm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/framework/ios/base/executors/HippyJSExecutor.mm b/framework/ios/base/executors/HippyJSExecutor.mm index 6b39a5f293c..ad540203868 100644 --- a/framework/ios/base/executors/HippyJSExecutor.mm +++ b/framework/ios/base/executors/HippyJSExecutor.mm @@ -265,9 +265,7 @@ - (void)injectDeviceInfoAsHippyNativeGlobal:(HippyBridge *)bridge context:(const std::shared_ptr &)context globalObject:(const std::shared_ptr &)globalObject { NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionaryWithDictionary:[bridge deviceInfo]]; - NSString *deviceName = [[UIDevice currentDevice] name]; - NSString *clientId = HippyMD5Hash([NSString stringWithFormat:@"%@%p", deviceName, self]); - NSDictionary *debugInfo = @{@"Debug" : @{@"debugClientId" : clientId}}; + NSDictionary *debugInfo = @{@"Debug" : @{@"debugClientId" : [self getClientID]}}; [deviceInfo addEntriesFromDictionary:debugInfo]; auto key = context->CreateString(kHippyNativeGlobalKey); @@ -354,6 +352,12 @@ - (void)registerGetTurboModuleFuncToJS:(const std::shared_ptr &)cont #pragma mark - +- (NSString *)getClientID { + NSString *deviceName = [[UIDevice currentDevice] name]; + NSString *clientId = HippyMD5Hash([NSString stringWithFormat:@"%@%p", deviceName, self]); + return clientId; +} + - (void)setUriLoader:(std::weak_ptr)uriLoader { if (self.pScope->GetUriLoader().lock() != uriLoader.lock()) { self.pScope->SetUriLoader(uriLoader); @@ -769,9 +773,7 @@ - (NSString *)completeWSURLWithBridge:(HippyBridge *)bridge { devInfo.versionId = bundleURLProvider.versionId; devInfo.wsURL = bundleURLProvider.wsURL; } - NSString *deviceName = [[UIDevice currentDevice] name]; - NSString *clientId = HippyMD5Hash([NSString stringWithFormat:@"%@%p", deviceName, bridge]); - return [devInfo assembleFullWSURLWithClientId:clientId contextName:bridge.contextName]; + return [devInfo assembleFullWSURLWithClientId:[self getClientID] contextName:bridge.contextName]; } From 007b7024d0c1888db8b74994346bc5578591facc Mon Sep 17 00:00:00 2001 From: zealotchen Date: Wed, 6 Nov 2024 21:37:33 +0800 Subject: [PATCH 02/10] fix(js): add NamedModulesPlugin --- .../hippy-react-demo/scripts/hippy-webpack.android-vendor.js | 1 + .../examples/hippy-react-demo/scripts/hippy-webpack.android.js | 1 + .../hippy-react-demo/scripts/hippy-webpack.ios-vendor.js | 1 + driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios.js | 1 + .../hippy-react-demo/scripts/hippy-webpack.web-renderer.dev.js | 1 + .../hippy-react-demo/scripts/hippy-webpack.web-renderer.js | 1 + .../examples/hippy-react-demo/scripts/hippy-webpack.web.dev.js | 1 + driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.js | 1 + .../hippy-vue-demo/scripts/hippy-webpack.android-vendor.js | 1 + .../js/examples/hippy-vue-demo/scripts/hippy-webpack.android.js | 1 + .../examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js | 1 + driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js | 1 + .../hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js | 1 + .../hippy-vue-next-demo/scripts/hippy-webpack.android.js | 1 + .../hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js | 1 + .../js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js | 1 + 16 files changed, 16 insertions(+) diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js index 3352ea03d3d..4dcfe8c83bf 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js @@ -18,6 +18,7 @@ module.exports = { library: 'hippyReactBase', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android.js index 0ec17eea641..20a4e1556a4 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.android.js @@ -22,6 +22,7 @@ module.exports = { // publicPath: 'https://xxx/hippy/hippyReactDemo/', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js index d452d0bd22b..2d6134ae4d7 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js @@ -18,6 +18,7 @@ module.exports = { library: 'hippyReactBase', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios.js index 481cbc5ab0a..ec799757cb5 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ios.js @@ -22,6 +22,7 @@ module.exports = { // publicPath: 'https://xxx/hippy/hippyReactDemo/', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.dev.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.dev.js index 793d00bb4ba..52f7c6867fa 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.dev.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.dev.js @@ -29,6 +29,7 @@ module.exports = { globalObject: '(0, eval)("this")', }, plugins: [ + new webpack.NamedModulesPlugin(), new HtmlWebpackPlugin({ inject: true, scriptLoading: 'blocking', diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.js index 376365e717a..d15bec933fd 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web-renderer.js @@ -17,6 +17,7 @@ module.exports = { path: path.resolve(`./dist/${platform}/`), }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.dev.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.dev.js index 29938d273bd..b3a6c539f7c 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.dev.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.dev.js @@ -25,6 +25,7 @@ module.exports = { path: path.resolve(`./dist/${platform}/`), }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('development'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.js index aa661369fc1..8a055cb4401 100644 --- a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.js +++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.web.js @@ -18,6 +18,7 @@ module.exports = { path: path.resolve(`./dist/${platform}/`), }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js index dd0a29d751d..7bd76b3a139 100644 --- a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js +++ b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js @@ -31,6 +31,7 @@ module.exports = { library: 'hippyVueBase', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android.js b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android.js index ae08ea81ea0..b7a42a1c073 100644 --- a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android.js +++ b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.android.js @@ -43,6 +43,7 @@ module.exports = { // publicPath: 'https://xxx/hippy/hippyVueDemo/', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js index 78b5ef6d2af..9d04455b698 100644 --- a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js +++ b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js @@ -31,6 +31,7 @@ module.exports = { library: 'hippyVueBase', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js index 891d9564a66..f16be6650ca 100644 --- a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js +++ b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js @@ -43,6 +43,7 @@ module.exports = { // publicPath: 'https://xxx/hippy/hippyVueDemo/', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js index 9c6a2163ff7..a8689aece99 100644 --- a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js +++ b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js @@ -19,6 +19,7 @@ module.exports = { library: 'hippyVueBase', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js index 3fc2de49fc3..c6188b5a3ca 100644 --- a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js +++ b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js @@ -31,6 +31,7 @@ module.exports = { // publicPath: 'https://xxx/hippy/hippyVueNextDemo/', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js index fdaa19a76ad..a23657ec9fb 100644 --- a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js +++ b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js @@ -19,6 +19,7 @@ module.exports = { library: 'hippyVueBase', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), diff --git a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js index c8fed863d6c..a8154d41539 100644 --- a/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js +++ b/driver/js/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js @@ -31,6 +31,7 @@ module.exports = { // publicPath: 'https://xxx/hippy/hippyVueNextDemo/', }, plugins: [ + new webpack.NamedModulesPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), __PLATFORM__: JSON.stringify(platform), From d6aa6b38f7b53f71ee6e8692f8846aa935d94f93 Mon Sep 17 00:00:00 2001 From: zealotchen Date: Wed, 6 Nov 2024 21:40:15 +0800 Subject: [PATCH 03/10] feat(vue-next): fix websocket event not bind --- .../hippy-vue-next/src/runtime/websocket/websocket.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/driver/js/packages/hippy-vue-next/src/runtime/websocket/websocket.ts b/driver/js/packages/hippy-vue-next/src/runtime/websocket/websocket.ts index 56291434bf5..77eb576a5e9 100644 --- a/driver/js/packages/hippy-vue-next/src/runtime/websocket/websocket.ts +++ b/driver/js/packages/hippy-vue-next/src/runtime/websocket/websocket.ts @@ -52,9 +52,6 @@ const WEB_SOCKET_MODULE_NAME = 'websocket'; // native event name for websocket const WEB_SOCKET_NATIVE_EVENT = 'hippyWebsocketEvents'; -// whether the websocket event listener has been bound -let isBindWebsocketEvent = false; - /** * determine whether it is a legitimate websocket event * @@ -116,11 +113,7 @@ class WebSocket { ...extrasHeaders, }; - if (!isBindWebsocketEvent) { - // The bus is global, if it is multi-instance, there may be problems, to be verified fixme - isBindWebsocketEvent = true; - EventBus.$on(WEB_SOCKET_NATIVE_EVENT, this.onWebSocketEvent); - } + EventBus.$on(WEB_SOCKET_NATIVE_EVENT, this.onWebSocketEvent); if (!url) { throw new TypeError('Invalid WebSocket url'); From a92892ed2c65cc8264954c2dc19d00212099c42d Mon Sep 17 00:00:00 2001 From: zealotchen <92966734+zealotchen0@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:37:03 +0800 Subject: [PATCH 04/10] chore(doc): add react vue performance doc (#4116) --- docs/api/_sidebar.md | 4 + docs/api/feedback.md | 92 ++++ docs/api/hippy-react/_sidebar.md | 4 + docs/api/hippy-react/customize.md | 10 +- docs/api/hippy-react/feedback.md | 18 + docs/api/hippy-react/modules.md | 4 + docs/api/hippy-vue/_sidebar.md | 3 + docs/api/hippy-vue/customize.md | 10 +- docs/api/hippy-vue/feedback.md | 28 + docs/api/hippy-vue/vue-native.md | 4 + docs/api/hippy-vue/web.md | 2 +- docs/api/performance.md | 763 ++++++++++++++++++++++++++- docs/api/style/_sidebar.md | 3 + docs/api/style/feedback.md | 22 + docs/development/native-component.md | 28 +- docs/development/report.md | 1 + 16 files changed, 969 insertions(+), 27 deletions(-) create mode 100644 docs/api/feedback.md create mode 100644 docs/api/hippy-react/feedback.md create mode 100644 docs/api/hippy-vue/feedback.md create mode 100644 docs/api/style/feedback.md diff --git a/docs/api/_sidebar.md b/docs/api/_sidebar.md index e3f5b9ca36c..9d174cd59a0 100644 --- a/docs/api/_sidebar.md +++ b/docs/api/_sidebar.md @@ -8,6 +8,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [React 常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -19,12 +20,15 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [Vue 常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [样式常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) +* [常见反馈](api/feedback.md) diff --git a/docs/api/feedback.md b/docs/api/feedback.md new file mode 100644 index 00000000000..56591147dab --- /dev/null +++ b/docs/api/feedback.md @@ -0,0 +1,92 @@ +# 常见反馈 + +## 1. Hippy提供了@hippy/react-web和Web Renderer两套方案,哪一套方案转web的能力更完整一些呢?Hippy后续会重点支持哪一个方向? + +两套方案都有一些业务在用, 组件和属性支持可以参考这两个文档 + +https://iwiki.woa.com/p/1478044741 + +https://iwiki.woa.com/p/1410007954 + +Hippy 会继续维护 Web Renderer,基于 Web Render,更容易对接 kbone 等来扩展小程序 + +## 2. Hippy 如何支持小程序 + +可以Hippy 对接 Kbone、taro、uniapp 等框架,腾讯内部业务可参考其他[业务方案](https://doc.weixin.qq.com/doc/w3_ANsAsgZ1ACcxxR1G3KPR0K85XYnmP?scode=AJEAIQdfAAoD1a4bp0ANsAsgZ1ACc): + +## 3. Hippy 的组件库有推荐吗 + +[开源仓库](https://github.com/hippy-contrib) + +[腾讯内部仓库](https://raftx.woa.com/hippy) + +## 4. Hippy 如何做曝光上报 + +目前 Hippy 还没有对外的曝光上报方案,腾讯内部的业务,可以使用大同来做曝光上报 + +### 方案 + +hippy本质上使用的还是客户端原生组件 以及一部分自绘组件。客户端已集成的的大同sdk能够对原生组件、Activity等做检测上报,自然也可以对hippy的组件做检测上报。重点处理上报id绑定到组件的逻辑就可以。 + +### 接入指引 + +[Hippy Android 曝光上报指引](https://iwiki.woa.com/p/956352478) + +[Hippy iOS 曝光上报指引](https://iwiki.woa.com/p/589637144) + +有疑问可以咨询企业微信 TDF小助手 + + +## 5. 启动时, Hippy 如何从终端获取参数 + +React 通过根节点的 props 获取启动参数 + +Vue 通过 Vue.$start 回调获取启动参数 + +## 6. Hippy 页面支持 width: auto 吗 + +不支持的,可以用imageloader加载读图片尺寸,https://hippyjs.org/#/hippy-vue/vue-native?id=imageloader + +## 7. Hippy 背景透明是否支持毛玻璃效果呢 + +腾讯业务可参考[社区组件](https://raftx.woa.com/hippy/detail/578) + +## 8. Hippy 如何实现暗黑模式 + +有两种方案: + +方案一:设置2套css属性,然后切换时整体切换,性能较差 + +方案二:初始化节点时,把两套属性都带下去,然后终端渲染时切换 + +## 9. Hippy 有提供类似 IntersectionObserver 方法吗 + +react 还不支持,vue有封装了一个,可以参考封装下 [hippy-vue-intersection-observer](https://www.npmjs.com/package/hippy-vue-intersection-observer) 不过这个库是基于hippy的Measure API实现的,对bridge通信性能会有一定性能影响,使用时注意评估下 + +## 10. Hippy 有 Clipboard 的复制剪切功能吗 + +剪切板相关的能力应该是在3.2移出的,其他版本可以参考文档:https://github.com/Tencent/Hippy/blob/v2.15.x/docs/hippy-react/modules.md#clipboard + +## 11. 我们现在前端用的是React技术栈,我们想一部分业务用Vue,一部分业务用React,Hippy支持这种用法吗 + +支持的,但是react 和 vue得是不同的hippy引擎实例 + +## 12. Hippy 如何判断横屏 + +进入app后,横屏切换会触发 onSizeChanged 事件 + +进入app前已经横屏,这个可以读 Vue.Native.Dimensions ,获取当前窗口长宽来计算,可以参考这个帖子 https://mk.woa.com/q/293192?ADTAG=search + +## 13. Hippy 图片必须要设定宽高吗?希望宽度和父级view一样,高度自适应怎么写呢 + +可以用 ImageLoaderModule.getSize 这个接口先获取图片大小 https://hippyjs.org/#/hippy-react/modules?id=imageloadermodule + +## 14. 执行报错 startBatch is not a function, 可能是什么原因 + +startBatch是 Hippy2 才有的版本,如果前端使用 Hippy2 终端使用 Hippy3 会不兼容,检查下@hippy/hippy-vue 的版本,确保和终端版本一致 + +## 15. Hippy 是否支持动态加载 + +支持,参考 https://doc.openhippy.com/#/feature/feature2.0/dynamic-import + + diff --git a/docs/api/hippy-react/_sidebar.md b/docs/api/hippy-react/_sidebar.md index e3f5b9ca36c..9d174cd59a0 100644 --- a/docs/api/hippy-react/_sidebar.md +++ b/docs/api/hippy-react/_sidebar.md @@ -8,6 +8,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [React 常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -19,12 +20,15 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [Vue 常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [样式常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) +* [常见反馈](api/feedback.md) diff --git a/docs/api/hippy-react/customize.md b/docs/api/hippy-react/customize.md index ed30972d492..971c9aa40aa 100644 --- a/docs/api/hippy-react/customize.md +++ b/docs/api/hippy-react/customize.md @@ -36,14 +36,20 @@ export class MyView extends React.Component { # 自定义模块 -> 该范例仅可以在 Android 下运行。 - 前端扩展模块分为三步: 1. 第一步导入 callNative 或者 callNativeWithPromise 接口 2. 封装调用接口 3. 导出模块 +注: callNative 代表前端调用客户端接口,无需返回 +callNativeWithPromise 代表前端调用客户端接口,需要返回,返回一个 Promise 对象 + +callNtive/callNativeWithPromise 参数含义: +moduleName: 代表和终端约定的模块名字,为 string 类型 +functionName: 代表和终端约定的模块函数名字,为 string 类型 +params: 实际携带参数, 为 Object 类型 + ```javascript // TestModule.js import { callNative, callNativeWithPromise } from "@hippy/react" diff --git a/docs/api/hippy-react/feedback.md b/docs/api/hippy-react/feedback.md new file mode 100644 index 00000000000..7e18764aa64 --- /dev/null +++ b/docs/api/hippy-react/feedback.md @@ -0,0 +1,18 @@ +# Hippy-React 常见反馈 + +## 1. 如何开始一个hippy react 项目 + +可以先参考我们的文档 和 demo + +https://hippyjs.org/#/hippy-react/introduction + +https://github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo + +## 2. Hippy 是否支持 React 函数式写法 + +目前 Hippy 已适配 React 17,已支持函数式写法,未来会持续 React 18、9 + +## 3. Hippy-React支持class吗,就向下面这样传统react开发一样 + +Hippy-React 不支持 classname, 只能通过内联 Style + diff --git a/docs/api/hippy-react/modules.md b/docs/api/hippy-react/modules.md index 67acc1194d0..5e2ae4e5eb5 100644 --- a/docs/api/hippy-react/modules.md +++ b/docs/api/hippy-react/modules.md @@ -433,6 +433,10 @@ AsyncStorage 是一个简单的、异步的、持久化的 Key-Value 存储系 > - method:方法名称,如 ListView 的 `scrollToIndex` > - options: 需传递的数据,如 ListView 的 `[xIndex, yIndex, animated]`,空时显式写 `[]` +注: 也可以传入 callback 参数,这个是 Hippy 内部 API, 不推荐使用,源码可参考: + +[callUIFunction接口实现源码](https://github.com/Tencent/Hippy/blob/main/driver/js/packages/hippy-react/src/modules/ui-manager-module.ts) + ### UIManagerModule.getElementFromFiberRef 获取元素 Ref 对应的 Element(类似DOM)。`hippy-react-web` 不支持。 diff --git a/docs/api/hippy-vue/_sidebar.md b/docs/api/hippy-vue/_sidebar.md index e3f5b9ca36c..c25dfe608ae 100644 --- a/docs/api/hippy-vue/_sidebar.md +++ b/docs/api/hippy-vue/_sidebar.md @@ -8,6 +8,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -19,12 +20,14 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) diff --git a/docs/api/hippy-vue/customize.md b/docs/api/hippy-vue/customize.md index a8e04624fcb..8ac9c16f575 100644 --- a/docs/api/hippy-vue/customize.md +++ b/docs/api/hippy-vue/customize.md @@ -124,10 +124,16 @@ component: { # 自定义模块 -> 该范例仅可以在 Android 下运行。 - hippy-vue 的模块其实只是一个 `Vue.Native.callNative` 调用,写个 `function` 即可。 +注: callNative 代表前端调用客户端接口,无需返回 +callNativeWithPromise 代表前端调用客户端接口,需要返回,返回一个 Promise 对象 + +callNtive/callNativeWithPromise 参数含义: +moduleName: 代表和终端约定的模块名字,为 string 类型 +functionName: 代表和终端约定的模块函数名字,为 string 类型 +params: 实际携带参数, 为 Object 类型 + ```js import Vue from 'vue'; diff --git a/docs/api/hippy-vue/feedback.md b/docs/api/hippy-vue/feedback.md new file mode 100644 index 00000000000..3cf187d0600 --- /dev/null +++ b/docs/api/hippy-vue/feedback.md @@ -0,0 +1,28 @@ +# Hippy-Vue 常见反馈 + +## 1. 如何开始一个hippy vue 项目 + +可以先参考我们的文档 和 demo + +https://hippyjs.org/#/hippy-vue/introduction +https://github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo + +## 2. Hippy Vue中span的换行符会被 trim + +3.x hippy-vue的版本,Hippy默认开启了 Vue.config.trimWhitespace 这个参数。而 hippy-vue 2.x的版本是不开的, 这个也是为了和未来 vue3 版本的规划对齐 +https://github.com/vuejs/core/pull/1600 + +方案建议: +a. 在 hippy.js 文件加一句 Vue.config.trimWhitespace = false,这样配置就和安卓版本完全对齐了。这个参数会对产物有一些影响,也可以让你们前端同事再重新评估一下。 + +b. 因为现在 hippy 没有提供换行组件 br标签 或者 white-space 的 css,如果需要换行,则不适用span,而是重新创建一个 text文本组件 + +## 3. hippy-vue-next-style-parser,这个包的作用 + +这个包用于处理 vue-next 的 css parse 和 match 逻辑 + +## 4. Hippy 是否支持 Vite 构建 + +已支持,目前只有腾讯内部版,腾讯业务可联系 TDF小助手 + + diff --git a/docs/api/hippy-vue/vue-native.md b/docs/api/hippy-vue/vue-native.md index da43ca625b4..d5bca3599d3 100644 --- a/docs/api/hippy-vue/vue-native.md +++ b/docs/api/hippy-vue/vue-native.md @@ -194,6 +194,10 @@ Vue.Native.AsyncStorage.getItem('itemKey'); > * method:方法名称,如 ListView 的 `scrollToIndex` > * options: 需传递的数据,如 ListView 的 `[xIndex, yIndex, animated]` +注: 也可以传入 callback 参数,这个是 Hippy 内部 API, 不推荐使用,源码可参考: + +[callUIFunction接口实现源码](https://github.com/Tencent/Hippy/blob/main/driver/js/packages/hippy-vue/src/runtime/native.ts) + --- # Clipboard diff --git a/docs/api/hippy-vue/web.md b/docs/api/hippy-vue/web.md index 046700833aa..8f58ee928f6 100644 --- a/docs/api/hippy-vue/web.md +++ b/docs/api/hippy-vue/web.md @@ -2,4 +2,4 @@ ## WebRenderer 方案 -Hippy 全新 [`WebRenderer`](web/integration.md) 方案,增加基于公共通信协议的转换层,业务开发者可以使用同一套 Hippy 语法开发的业务代码,映射成 JS 实现的组件和模块,上层无论使用 React,Vue 或者其他第三方框架,都可以实现兼容,可参考。 +Hippy 全新 [`WebRenderer`](development/web-integration-guidelines.md) 方案,增加基于公共通信协议的转换层,业务开发者可以使用同一套 Hippy 语法开发的业务代码,映射成 JS 实现的组件和模块,上层无论使用 React,Vue 或者其他第三方框架,都可以实现兼容,可参考。 diff --git a/docs/api/performance.md b/docs/api/performance.md index 4a8c51a744a..60b72a92873 100755 --- a/docs/api/performance.md +++ b/docs/api/performance.md @@ -1,22 +1,759 @@ -# 性能监控 +# **Hippy 业务冷启动性能优化指引** -提供全局 `performance` 对象,用于获取性能数据。 +## **背景** ---- +经常有业务咨询 Hippy 有哪些优化手段,以及业务性能问题应该怎么分析,有哪些监控工具,本篇文档则系统的介绍了 Hippy 冷启动的性能优化的最佳实践。 -# memory -`performance.memory` 返回 js 引擎中内存的统计数据(仅 Android 支持,iOS 将返回 `undefined` )。 -> 最低支持版本 `2.15.0` -```javascript +## **冷启动阶段:** -global.performance.memory = undefined || { - jsHeapSizeLimit: 4096, // 堆内存大小限制 - totalJSHeapSize: 2048, // 可使用的堆内存 - usedJSHeapSize: 1024, // 已使用的堆内存 - jsNumberOfNativeContexts: 1, // 当前活动的顶层上下文的数量(随着时间的推移,此数字的增加表示内存泄漏) - jsNumberOfDetachedContexts: 0, // 已分离但尚未回收垃圾的上下文数(该数字不为零表示潜在的内存泄漏) +介绍一下Hippy应用冷启动有哪些阶段 + +​ 1. Hippy 运行环境启动 - 终端耗时 (启动) + +​ 2. 加载 Bundle的 JS 文件 - JS 引擎耗时 (自执行) + +​ 3. 应用实例的执行 - JS 引擎耗时(JS运行) + +​ a. 业务代码逻辑执行 + +​ b. 业务 IO(网络、JS API)等待 + +​ c. React/Vue 框架 DIFF 耗时 + +​ d. Hippy JS SDK计算耗时 + +​ 4. 上屏显示 - 终端耗时 (渲染) + +​ a. Hippy DOM 构建、排版耗时 + +​ b. Hippy 渲染上屏耗时 + +详细介绍参考:[Hippy冷启动核心逻辑和数据梳理](https://doc.weixin.qq.com/doc/w3_AJcAmQbdAFwmCbIe8OPScGUN6amkw?scode=AJEAIQdfAAo1QKXNGAAJcAmQbdAFw) + +我们把启动阶段分为 4个阶段:Hippy 启动、Bundle加载、**应用实例执行**、渲染上屏。 + +不同规模的 Hippy 业务,这些阶段耗时不尽相同,大家可以先测试各阶段耗时占比,再针对性的来分析。 + + + +Hippy 团队过去有一些经验可供参考: + +​ 1. 一般耗时大头是阶段 3 (一半耗时占比超过 50%) + +业务可重点排查 **业务 JS 执行耗时**、**IO(网络、JS API)等待耗时。**此外,**节点数过多、CSS 属性比较复杂**,也会影响 Hippy SDK的计算耗时 + +​ 2. JS Bundle包过大,会影响阶段 2 的耗时 + +​ 3. 节点数过多,节点层级比较深,渲染样式比较复杂,会影响阶段 3 的耗时 + + + +## **如何监控定位:** + +### **1.** **线上监控:** + +​在 Hippy 3.0,我们设计了用于性能分析的 Performance API: + +[Hippy 性能监控设计文档](https://doc.weixin.qq.com/doc/w3_ANsAsgZ1ACcBlbHY905RpW7Qj1vij?scode=AJEAIQdfAAosjxQAlNANsAsgZ1ACc) + + + +Performance API 冷启动打点指标: + +| **指标** | **对应 Key** | +| -------------------- | ------------------------ | +| Hippy 引擎加载开始 | hippyNativeInitStart | +| JS 引擎加载开始 | hippyJsEngineInitStart | +| JS 引擎加载结束 | hippyJsEngineInitEnd | +| Hippy 引擎加载结束 | hippyNativeInitEnd | +| JS Bundle 自执行耗时 | bundleInfo[] | +| 业务入口执行开始 | hippyRunApplicationStart | +| 业务入口执行结束 | hippyRunApplicationEnd | +| 首帧绘制开始 | hippyFirstFrameStart | +| 首帧绘制结束 | hippyFirstFrameEnd | +| 启动耗时 | duration | + + + +监控方式: + +​ 1. Hippy 3.x版本:可以接入最新 aegis-sdk (咨询 TDF小助手),已经基于 performance api,可以直接获取打点数据 + + + +​ 2. Hippy 2.x 版本可以基于业务代码打点,获取启动阶段的近似耗时数据。可参考:https://km.woa.com/articles/show/557810?kmref=search&from_page=1&no=1 + + + +### **2.** **Profile 工具:** + +​ 1. Perfdog + +​ a. 可查看 FPS, CPU, GPU, 内存等变化情况 + +​ 2. 安卓系统自带工具: + +​ a. GPU 渲染模式分析: 通过在 Android 设备的设置 APP 的开发者选项里打开 “ GPU 渲染模式分析” 选项,选择 ” 在屏幕上显示为条形图 “ 。 + +​ b. 过度绘制:Android 设备的设置 APP 的开发者选项里打开 “ 调试 GPU 过度绘制 ” + +​ c. 查看界面边界:系统设置 – 开发者选项 – 绘图 --显示布局边界 + +​ 3. iOS系统 simulator 模拟器 + +​ a. Debug 下自带分析工具 Color Blended Layers 图层绘制 Color Off-screen Rendered 离屏渲染 + +​ 4. Profile工具 + +​ a. Android Studio Profiler + +​ b. Xcode Instruments + +​ **c.** **Hippy Devtools (也在进一步完善中,欢迎大家提需求),如下示例:** + + + +**如何优化:** + +定位到耗时点,接下来就可以针对性分析。 + +先简单介绍常用的优化: + +​ 1. 预加载:大幅降低 1-2 阶段耗时 + +​ 2. 预渲染/SSR/Native-Vue:大幅降低 1-3阶段耗时 + +​ 3. 数据预拉取:降低 3阶段 IO 等待耗时 + +​ 4. JSI、动态加载、节点数优化:降低 3 阶段耗时 + +​ 5. 节点缓存/渲染优化/图片缓存:降低 4 阶段耗时 + +​ 6. 骨架屏优化/Loading:优化交互体验 + +... + + + +接下来详细介绍这些优化点: + + + +### **1.** **预加载** + +通过提前执行1+2阶段逻辑优化首屏耗时。 + +这两个阶段耗时主要被封装在HippyBridge中,因此可以通过提前初始化HippyBridge达成目的。 + + + +iOS 代码示例: + +``` javascript +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:nil bundleURL:url moduleProvider:^NSArray> * { + return nil; // 或返回希望替换的module实例 +} launchOptions:option executorKey:nil]; + +// 将bridge保存起来 +``` + +安卓代码示例: + +``` javascript +mHippyEngine.initEngine(new HippyEngine.EngineListener() { + @Override + public void onInitialized(EngineInitStatus statusCode, String msg) { + if (statusCode == EngineInitStatus.STATUS_OK) { + HippyBundleLoader loader = ...; + // e.g.: + // new HippyAssetBundleLoader(context, assetName, true, "demo"); + // new HippyFileBundleLoader(filePath, true, "demo"); + mHippyEngine.preloadModule(loader); + } + } } +``` + + +优点: + +​ 1. 不依赖页面数据,在任何页面都可考虑使用预加载 + +​ 2. 前端也可以在预加载时提前fetch数据 + +缺点: + +​ 1. 优化效果相对预渲染不够明显 + + + +### **2.** **预渲染** + +如果还希望在预加载基础上继续优化体验,还可以进一步提前执行步骤 3 的逻辑。 + +优点: + +​ 1. 优化效果十分明显 + +缺点: + +​ 1. 内存开销大 + +​ 2. 无法对动态数据的页面使用 + +​ 3. 页面发版会导致命中率降低 + +​ 4. 预渲染时的Dimension可能与访问时不一致,导致布局异常 +​ 5. 在Android上预渲染只能使用AppContext,导致页面打开后也无法使用依赖Activity的能力,例如Modal(Dialog)组件 + + + +接入代码示例: + +iOS 代码示例 + + + +``` javascript +HippyRootView *hippyRootView = [[HippyRootView alloc] + initWithBridge:bridge + businessURL:businessURL + moduleName:appName + initialProperties:properties + delegate:delegate]; +// 将hippyRootView保存起来 ``` + + + + + +执行这一步后,HippyRootView内部将会执行实例的加载,但由于rootView未被真正挂在到VC的UI树上,所以暂时不可见。 + +当需要显示的时候可以在VC的view上将hippyRootView加为子view。 + + + +``` javascript +[parent addSubview:hippyRootView]; + +// 必要时可以更新一下frame +hippyRootView.frame = newFrame; + +// 如果在addSubview后还有其他的subview的添加,可以考虑通过bringSubviewToFront将hippyRootView改为最前方显示 +[parent bringSubviewToFront:hippyRootView]; +``` + + + + + + + +安卓代码示例: + +除了需要把 ModuleLoadParams.context 设置为 AppContext 外,其余步骤和常规加载一致。 + + + +``` javascript +HippyEngine.ModuleLoadParams loadParams = new HippyEngine.ModuleLoadParams(); +loadParams.context = getApplicationContext(); +... +mHippyView = mHippyEngine.loadModule(loadParams, listener, null); +``` + + + + + +### **3.** **SSR** + +SSR 代替预渲染方案的另一选择。 + +方案原理:把 1-3 阶段放在服务端执行,解析成最终的 Hippy指令 的字符串,启动时直接反序列化 Hippy指令,下发Hippy终端执行渲染。 + +优化效果:性能数据与预渲染接近 + +详见QQ游戏中心优化 https://km.woa.com/articles/show/564026?kmref=search&from_page=1&no=1 + + + +优点: + +​ 1. 可不依赖终端方案方案,前端执行 + +​ 2. 相比预渲染方案更节省内存 + +缺点: + +​ 1. 需要执行事件挂载逻辑,可交互时间会延迟 + +​ 2. 会带来服务器的运营成本 + + +### **4.** **数据预请求:** + +在不方便应用 预渲染/SSR/Native-Vue的场景。可以考虑提前下载数据,节省 3阶段 网络 IO 耗时: + +​ 1. 可以在终端预请求,在启动Hippy后,把数据传给前端 + +​ 2. 可以结合预加载,在前端 JS 自执行阶段,前端预请求数据。等待组件渲染时直接使用。 + + + +### **5.** **节点缓存** + +​ 1. Dom Node 缓存(安卓) + +接入方案详见:https://doc.openhippy.com/#/feature/feature2.0/dom-cache + +​ 2. RenderNode 缓存(3.0 安卓) + +接入方案详见:https://doc.openhippy.com/#/feature/feature3.0/render-node-snapshot + + + + + +### **6.** **JS 引擎优化** + +在不方便做 JS 预加载的场景,如果要优化 JS 自执行耗时,可以考虑对 JS 引擎本身做优化: + +#### **6.1.** **V8 编译开启 Code Cache** + +把编译和解析的结果缓存下来,等到下次遇到相同的文件,直接跳过这个过程,把直接缓存好的数据拿来使用; + +​Hippy 2.0: Hermes 接入指引文档:https://iwiki.woa.com/p/4007348225 + +​Hippy 3.0 Hermes会直接集成,文档待补充。 + + + + + +### **7.** **bundle 包动态加载** + +接入文档指引:https://iwiki.woa.com/p/491739348 + +Hippy 打包插件只支持一个jsbundle包的生成。随着业务逻辑越来越复杂,jsbundle越来越大、包的加载时间越来越长。为了解决这个问题,Hippy 在 2.2.0 版本增添了动态加载能力,Hippy 的开发人员可以按照业务需求来动态引入 JS。 + +Hippy 在 2.5.5 版本增加了远程网络加载模式的支持,业务可对每个bundle自定义不同的加载模式。 + + + +webpack打包脚本中引入插件:HippyDynamicImportPlugin + + + +``` javascript +const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin'); + +module.exports = { + ... + plugins: [ + new HippyDynamicImportPlugin(), + ], +}; +``` + + + + + + + +​ (1)加载本地 JS 包: + +​ 与 Web 开发动态加载能力一样,直接使用 import() 语法即可 + + + +​ (2)加载远程 JS 包: + + i. webpack打包脚本配置全局 publicPath(可选) + + + +``` javascript + // webpack output 配置 + output: { + ... + publicPath: 'https://xxxx/hippy/hippyVueDemo/', +}, +``` + + + + + +ii. 在业务代码引用分包的入口配置 magic comment的 webpackChunkName(必须) 和 customChunkPath(可选),如果没有配置customChunkPath,会默认使用全局 publicPath; 以 Hippy-Vue 为例: + + + +``` javascript + // Hippy-Vue 配置 + AsyncComponentFromHttp: () => import(/* customChunkPath: "https://xxx/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') + .then(res => res) + .catch(err => console.error('import async remote component error', err)) +``` + + + + + + + + + +### **8.** **JS API 优化** + +#### **8.1.** **JS Bridge -> JSI** + +​接入方案详见:https://doc.openhippy.com/#/feature/feature2.0/jsi + +​优化效果: + +Android 代码示例: + + + +``` javascript +// 初始化引擎开启 enableTurbo +val initParams = HippyEngine.EngineInitParams() +initParams.enableTurbo = true + +// 定义 module +@HippyNativeModule(name = "demoTurbo") +class DemoTurboModule(context: HippyEngineContext?) : HippyNativeModuleBase(context) { + ... + @HippyMethod(isSync = true) + fun getNum(num: Double): Double = num + ... +} +``` + + + + + +​iOS 代码示例: + + + +``` javascript +// 方式一:bridge初始化时通过配置参数设置生效 +NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO)}; +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:[NSURL fileURLWithPath:commonBundlePath] + moduleProvider:nil + launchOptions:launchOptions + executorKey:@"demoTurbo"]; + +// 方式二:bridge初始化完成后,设置属性生效 +HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:nil + businessURL:nil + moduleName:@"demoTurbo" + initialProperties:@{@"isSimulator": @(isSimulator)} + launchOptions:nil + shareOptions:nil + debugMode:YES + delegate:nil]; +rootView.bridge.enableTurbo = YES; +``` + + + + + + + +``` javascript +@implementation TurboConfig + +... + +// 注册模块 +HIPPY_EXPORT_TURBO_MODULE(TurboConfig) + +// 注册交互函数 +HIPPY_EXPORT_TURBO_METHOD(getInfo) { + return self.strInfo; +} +HIPPY_EXPORT_TURBO_METHOD(setInfo:(NSString *)string) { + self.strInfo = string; + return @(YES); +} + +... + +@end +``` + + + + + + + +Hippy-React 代码示例: + +https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/externals/Turbo/demoTurbo.js + +Hippy-Vue 代码示例: + +https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demoTurbo.js + + + +#### **8.2.** **减少首屏 JS API 调用次数** + + + +### **9.** **Hippy-Vue 优化** + +​ 1. 减少 getElemCss 方法的调用 + + + +``` javascript +Vue.Native.getElemCss() +``` + + + + + +​ 2. 减少 scoped 的使用 + +vue scoped 能力是 2.15.0 版本引入,scoped会转换为 属性选择器,因此解析性能会比较差; + +在 Hippy 3.0 版本,我们使用 css-module的方案优化了 scoped的解析方式,性能得到提升。 + +​ 3. 减少 CSS 属性选择器、伪类等样式的使用 + +​ 4. 升级 Hippy-Vue-Next(Vue3) + +Vue3 升级指引:https://hippyjs.org/#/hippy-vue/vue3 + +Vue3 相比 Vue2 做了 Diff算法优化、静态提升、事件缓存等优化,从Vue框架层面会带来性能提升。实测了 Vue3 和 Vue2 在Hippy框架下的数据对比: + + + +### **10. Hippy-React 优化** + +​ 1. Hippy React节点更新优化: + +https://iwiki.woa.com/p/1335183393 + +@hippy/react 在 2.12.0 版本应用上了最新的渲染优化,针对 react 16 和 react 17,先删除原来的 react-reconciler 包依赖,再分别引入 + + + +``` javascript +"@hippy/react-reconciler": "react16" +"@hippy/react-reconciler": "react17" +``` + + + + + +​ + +### **11.** **渲染优化:** + +#### 1. 减少首屏节点数、节点层级 + +- 可以借助客户端 IDE 来直观地查看 "DOM" 树,使用前端的 DevTools 的 View 树来检查冗余节点。 + +#### 2. 减少节点重复渲染的次数 + +- 可以在高频渲染节点的 `render` 函数中打点统计。 +- 使用 `shouldComponentUpdate`、`PureComponent` 等优化重复渲染。 + +#### 3. 节点优化:节点合并,扁平化(触发 Hippy 引擎优化) + +- 减少冗余事件挂载。 + +#### 4. 圆角、裁剪、描边等渲染性能较差,尽量减少使用 + +#### 5. 减少过度绘制 + +- 移除重复的背景色。 +- 减少图层覆盖。 + +#### 6. ListView + +- 尽量使用 `ListView` 代替 `ScrollView`,`ListView` 通过 View 的缓存与重用大大提升渲染性能。 +- 使用 `getRowType`,将 item 按类型合理拆分,同一类型的 item 的 `RowType` 相同,可复用。 +- 严格保持 `ListView` item 的 DOM 结构一致: + - **hippy-vue**:item 中的节点可以用 `v-show`,不要用 `v-if`。 + - **hippy-react**:item 中的节点尽量不要用 `if` 条件来改变节点结构。 + +#### 7. ViewPager + +- `ViewPager` 的子节点尽量不要全加载,实现懒加载。 + +#### 8. Image + +- 图片压缩。 +- 图片按需加载。 +- 避免同时使用 `src` 和 `background`。 +- 大图放 CDN。 +- 减少 base64 图片使用。 +- 图片缓存(内存缓存、磁盘缓存)。 + +​ 代码示例:在自定义ImageLoader中实现自己的缓存逻辑,也可使用第三方图片加载库,如 slide 等。 + + + +``` javascript +HippyEngine.EngineInitParams initParams = new HippyEngine.EngineInitParams(); +// 必须:宿主(Hippy的使用者)的Context +// 若存在多个Activity加载多个业务jsbundle的情况,则这里初始化引擎时建议使用Application的Context +initParams.context = this; +... +// 必须:图片加载器 +initParams.imageLoader = new MyImageLoader(this.getApplicationContext()); +``` + + + + + + + +### **12.** **业务逻辑执行优化** + +此外,也要检查业务代码自身的耗时,并做针对性优化。 + +​ 1. 防抖节流:对滚动事件、数据上报等进行防抖节流,避免频繁触发计算 + +​ 2. 耗时逻辑检查是否可以放在首屏后执行 + + + +### **13.** **交互优化** + +除了上面的优化手段,交互优化在一些场景也是十分重要的,可以提升打开体验,让页面视觉上更流畅。 + +​ 1. 骨架屏优化 + +​ 2. Loading + +​ 3. 切换动画 + + + +## **总结:** + +优化总结、是否需要 终端/前端 同学支持。 + +| 优化方案 | 方案介绍 | 接入成本 | 优化效果 | 终端/前端工作 | +| -------------------- | ------------------------------ | -------- | ---------- | -------------- | +| 预加载 | 优化 JS Bundle包加载 | 中 | 中 | 终端工作 | +| 预渲染 | 基于预加载,进一步优化渲染耗时 | 中 | 好 | 终端工作 | +| SSR | 预渲染的替代方案 | 中 | 好 | 前端工作 | +| Native-Vue | 预渲染的另一种替代方案 | 高 | 好 | 前端工作 | +| 数据预请求 | 节省 IO 耗时 | 低 | 中 | 终端或前端工作 | +| 节点缓存 | 仅安卓支持,优化渲染耗时明显 | 低 | 中 | 终端工作 | +| JS引擎优化(Hermes) | 性能比JSC优化明显 | 高 | 好 | 终端工作 | +| Bundle动态加载 | 分包加载,节省 JS 执行耗时 | 中 | 中 | 前端工作 | +| JS API优化(JSI) | JSI 接口同步调用,等待耗时降低 | 低 | 中 | 前端工作 | +| Hippy-Vue 逻辑优化 | 优化 css 解析耗时 | 低 | 好 | 前端工作 | +| Hippy-React 逻辑优化 | 渲染队列优化 | 低 | 中 | 前端工作 | +| 渲染优化 | 组件使用的渲染耗时优化 | 低 | 中 | 前端工作 | +| 业务逻辑优化 | 业务自身逻辑优化 | 无 | 中 | 前端工作 | +| 交互优化 | 业务自身优化交互 | 无 | 体验上优化 | 前端工作 | + + + +## **参考资料:** + +​ 1. K歌 Hippy性能优化分享(一) + +https://km.woa.com/articles/show/511822?kmref=search&from_page=1&no=7 + +​ 2. k歌 Hippy性能优化分享(二) + +https://km.woa.com/articles/show/484172?kmref=search&from_page=1&no=5 + +​ 3. k歌 Hippy性能优化分享 (三) + +https://km.woa.com/articles/show/504866?kmref=search&from_page=1&no=3 + +​ 4. k歌渲染优化 + +https://km.woa.com/articles/show/465625?kmref=search&from_page=1&no=2 + +​ 5. 小说 Hippy性能优化 + +https://km.woa.com/articles/show/484172?kmref=search&from_page=1&no=5 + +​ 6. 浏览器小说阅读器内存优化 + +https://km.woa.com/articles/show/468088?kmref=search&from_page=1&no=6 + +​ 7. QQ 增值Hippy性能优化 + +https://km.woa.com/articles/show/516658?kmref=search&from_page=1&no=4 + +​ 8. QQ直播Hippy性能优化 + +https://km.woa.com/articles/show/557810?kmref=search&from_page=1&no=1 + +​ 9. QQ游戏中心Hippy SSR优化 + +https://km.woa.com/articles/show/564026?kmref=search&from_page=1&no=1 + +​ 10. QQ 音乐Hippy性能监控工具建设 + +https://km.woa.com/articles/show/494153?kmref=search&from_page=1&no=6 + +​ 11. 浏览器 Hermes 引擎优化性能 + +https://km.woa.com/articles/show/567715?kmref=search&from_page=1&no=4 + +​ 12. QB长视频业务优化-接入Hermes引擎 + +https://km.woa.com/articles/show/564575?kmref=search&from_page=1&no=7 + +​ 13. Hippy 内存、CPU性能优化 + +https://km.woa.com/articles/show/484158?kmref=search&from_page=1&no=8 + +​ 14. 闪现社区首屏优化 + +https://km.woa.com/articles/show/474636?kmref=search&from_page=1&no=9 + +​ 15. NativeVue:解决Hippy等类RN框架首屏白屏的极致方案 + +https://km.woa.com/articles/show/527262?kmref=search&from_page=1&no=10 + +​ 16. Hippy profile工具实现的思考 + +https://km.woa.com/articles/show/397231?kmref=search&from_page=1&no=6 + +https://km.woa.com/articles/show/445938 + +​ 17. 记一次Hippy-React优化 + +https://km.woa.com/articles/show/431695?kmref=search&from_page=1&no=9 + +​ 18. Flutter性能优化最佳实践 + +[Flutter 应用性能优化最佳实践 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter](https://flutter.cn/docs/perf/best-practices) + +​ 19. React Native 性能综述 + +[性能综述 · React Native 中文网](https://reactnative.cn/docs/performance) + +​ 20. 营地性能优化 + +https://km.woa.com/articles/show/599930?kmref=search&from_page=1&no=10 + + diff --git a/docs/api/style/_sidebar.md b/docs/api/style/_sidebar.md index 31e08a29e76..dda9aa7c24b 100644 --- a/docs/api/style/_sidebar.md +++ b/docs/api/style/_sidebar.md @@ -9,6 +9,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -20,12 +21,14 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) diff --git a/docs/api/style/feedback.md b/docs/api/style/feedback.md new file mode 100644 index 00000000000..e8b37e03db5 --- /dev/null +++ b/docs/api/style/feedback.md @@ -0,0 +1,22 @@ +# CSS 样式常见反馈 + +## 1. Hippy 设置百分比失效 + +Hippy 自研了排版引擎 [Taitank](https://github.com/Tencent/taitank), 为了追求极致的性能, 阉割了百分比的实现。 +常见场景实现方案参考: + +> 需要设置高度 100% + +可设置 flex: 1 + +> 需要设置宽度 50% + +可通过 Dimensions.screen 接口获取屏幕尺寸大小,然后计算相应百分比值 + +> 需要百分比实现 + +可以终端修改编译设置,把排版引擎切换为 [Yoga](https://doc.openhippy.com/#/feature/feature3.0/layout) + +## 2. hippy支持 css var 的写法吗 + +可以先用 postcss 相关的插件来支持 diff --git a/docs/development/native-component.md b/docs/development/native-component.md index 2bbf6c68c64..3d242874b6c 100644 --- a/docs/development/native-component.md +++ b/docs/development/native-component.md @@ -632,14 +632,14 @@ Widget build(BuildContext context) { 扩展组件主要包括: -1. 扩展 `HippyView` +1. 扩展 `HippyWebView` 2. 实现构造方法 3. 实现设置自定义组件的 `tagName` 4. 实现构造自定义组件的 `dom` 5. 实现自定义组件的 `API 能力` 6. 实现自定义组件的属性 -其中 `HippyView` 类,实现了一些 HippyBaseView 的接口和属性定义,在一个自定义组件中有几个比较重要的属性: +其中 `HippyWebView` 类,实现了一些 HippyBaseView 的接口和属性定义,在一个自定义组件中有几个比较重要的属性: - id: 每一个实例化 component 的唯一标识,默认会赋值给组件 dom 的 id 属性 - pId: 每一个实例化 component 的父组件标识 @@ -647,6 +647,16 @@ Widget build(BuildContext context) { - dom: 真正挂载到document上的节点 - props: 承载了从业务侧传递过来的属性和style的记录 +注: tagName 用来和 React/Vue 注册的自定义组件的 nativeName 关联,可参考: + +### 如果您使用的是`hippy-vue` + +可以参考 [hippy-vue/customize](api/hippy-vue/customize) + +### 如果您是用的是`hippy-react` + +可以参考 [hippy-react/customize](api/hippy-react/customize) + ### 例子 下面这个例子中,我们创建了 `CustomView` 的自定义组件,用来显示一个视频 @@ -655,10 +665,10 @@ Widget build(BuildContext context) { ```javascript -import { HippyView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; +import { HippyWebView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; -// 继承自 `HippyView` -class CustomView extends HippyView { +// 继承自 `HippyWebView` +class CustomView extends HippyWebView { // 实现构造方法 constructor(context, id, pId) { super(context, id, pId); @@ -682,9 +692,9 @@ class CustomView extends HippyView { ```javascript -import { HippyView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; +import { HippyWebView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; -class CustomView extends HippyView { +class CustomView extends HippyWebView { set src(value) { this.dom.src = value; @@ -735,7 +745,7 @@ Node.removeChild(child: T): T; - 如果组件不希望以这种默认的形式来实现,可以自行通过 `insertChild` 和 `removeChild` 方法管理节点的插入和移除逻辑。 ```javascript -class CustomView extends HippyView{ +class CustomView extends HippyWebView{ insertChild (child: HippyBaseView, childPosition: number) { // ... } @@ -750,7 +760,7 @@ class CustomView extends HippyView{ > 例子中,`data` 是组件本次更新的 `props` 数据信息,`defaultProcess()` 是 `HippyWebRenderer` 默认处理 `props` 更新的方法,开发者可以在这里拦截修改更新的数据后,依然使用默认的 `props` 进行更新,也可以不用默认的方法自行进行属性更新的遍历操作。 ```javascript -class CustomView extends HippyView{ +class CustomView extends HippyWebView{ updateProps (data: UIProps, defaultProcess: (component: HippyBaseView, data: UIProps) => void) { // ... diff --git a/docs/development/report.md b/docs/development/report.md index c5262bf1a20..2adda06e1ed 100644 --- a/docs/development/report.md +++ b/docs/development/report.md @@ -13,6 +13,7 @@ hippy本质上使用的还是客户端原生组件 以及一部分自绘组件 ## 接入指引 [Hippy Android 曝光上报指引](https://iwiki.woa.com/p/956352478) + [Hippy iOS 曝光上报指引](https://iwiki.woa.com/p/589637144) 有疑问可以咨询企业微信 TDF小助手 From 86aa2fb82368bdcb7b331f6e50deb038637a2873 Mon Sep 17 00:00:00 2001 From: maxli Date: Thu, 7 Nov 2024 16:57:52 +0800 Subject: [PATCH 05/10] fix(doc): update android v8 and module document --- docs/development/_sidebar.md | 2 +- docs/development/native-module.md | 46 +++++++++++++++---------------- docs/development/v8-api.md | 24 ++++++++++++++++ 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/docs/development/_sidebar.md b/docs/development/_sidebar.md index c30b77fbb61..5f1fef08ef3 100644 --- a/docs/development/_sidebar.md +++ b/docs/development/_sidebar.md @@ -15,7 +15,7 @@ - [事件](development/native-event.md) - [终端能力适配](development/native-adapter.md) - [数据类型映射](development/type-mapping.md) -- [V8 API](development/v8-api.md) +- [V8初始化参数与API](development/v8-api.md) - [调试](development/debug.md) - [曝光上报](development/report.md) - [技术支持](development/support.md) diff --git a/docs/development/native-module.md b/docs/development/native-module.md index 364f53a8cad..aa12b911f1a 100644 --- a/docs/development/native-module.md +++ b/docs/development/native-module.md @@ -117,35 +117,19 @@ public void helloNativeWithPromise(HippyMap hippyMap, Promise promise) } ``` - - ## 4. 注册Module -然后需要注册这个Module。需要在 `HippyPackage` 的 `getNativeModules` 方法中添加这个 Module,这样它才能在JS中被访问到。 +需要自定义'APIProvider'类,并实现SDK HippyAPIProvider interface,然后在`getNativeModules` 方法中添加这个 Module,这样它才能在JS中被访问到。 ```java -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyPackage; -import com.tencent.mtt.hippy.common.Provider; -import com.tencent.mtt.hippy.example.module.TestModule; - -import com.tencent.mtt.hippy.modules.javascriptmodules.HippyJavaScriptModule; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.uimanager.HippyViewController; +public class MyAPIProvider implements HippyAPIProvider { -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ExamplePackages implements HippyPackage -{ @Override - public Map, Provider> getNativeModules(final HippyEngineContext context) + public Map, Provider> getNativeModules(final HippyEngineContext context) { Map, Provider> modules = new HashMap<>(); - - // regist the LogModule - modules.put(ToastModule.class, new Provider() + //regist the MyModule + modules.put(TestModule.class, new Provider() { @Override public HippyNativeModuleBase get() @@ -153,11 +137,27 @@ public class ExamplePackages implements HippyPackage return new TestModule(context); } }); - - return modules; } + + @Override + public List> getJavaScriptModules() {return null;} + + @Override + public List> getControllers() {return null;} +} +``` + +## 5. 注册APIProvider + +在HippyEngine初始化的EngineInitParams参数属性中设置providers。 + +``` java +List providers = new ArrayList<>(); +providers.add(new MyAPIProvider()); +initParams.providers = providers; ``` + ## 注意事项 扩展Module中不能同步执行耗时操作,这可能卡住整个引擎通信线程。存在耗时场景,请使用异步线程处理。 diff --git a/docs/development/v8-api.md b/docs/development/v8-api.md index 01fdb5a7000..838435fc8e1 100755 --- a/docs/development/v8-api.md +++ b/docs/development/v8-api.md @@ -1,3 +1,27 @@ +# V8 相关初始化参数 + +在HippyEngine初始化的时候,EngineInitParams属性里有以下v8相关的属性参数。 + +## codeCacheTag + +code cache 是V8中的一个特性,简单说就是JavaScript代码在执行前,需要进行解析和编译,才能正确执行,解析编译过程是耗时的,V8 暴露了一个方法,可以将编译产物序列化存储下来,下次再执行相同一段代码时,就可以用之前缓存的内容,节省了解析编译的时间,codeCacheTag作为编译内容缓存的key,设置后便会开启v8 code cache能力,建议开发者对该初始化参数进行设置,可以有效降低非首次启动js bundle加载运行耗时。 + +## v8InitParams + +- initialHeapSize代表v8初始Heap size +- maximumHeapSize代表v8最大Heap size + +由于v8的内存是自己管理的,使用策略是尽可能使用更多的内存,只有在达到maximumHeapSize 80%左右的时候才会触发gc,未达到之前会一直增长,达到80%触发gc的同时会回调near_heap_limit_callback接口获取内存增量,这里内存增量通过sdk内部接口V8VMInitParam::HeapLimitSlowGrowthStrategy返回,默认内存增长策略是当前max值*2,如果前端申请大内存,扩容后还不满足内存分配就会产生OOM. + +在无限滚动列表场景,设置maximumHeapSize可以有效降低v8内存增加速率。 + +修改v8初始内存参数虽然能减少内存增量,但频繁的内存申请和gc,可能引入以下2个负面影响: + +- 首屏性能下降 +- OOM率升高 + +所以v8初始化内存参数的设置需要跟进具体的业务场景设置合适的值,并做完整的测试验证,如果不是内存占用有严格要的求场景不建议设置该初始化参数。 + # V8 API 获取 V8 JS 引擎对象,并操作相关方法。 From b9006fa820ad6ccdfaf50cffdfae4018a9d72725 Mon Sep 17 00:00:00 2001 From: etkmao Date: Thu, 7 Nov 2024 17:35:34 +0800 Subject: [PATCH 06/10] fix(core): fix invalid animation crash (#4117) --- dom/src/dom/animation/animation_manager.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dom/src/dom/animation/animation_manager.cc b/dom/src/dom/animation/animation_manager.cc index 566c0379155..72bd39c9b36 100644 --- a/dom/src/dom/animation/animation_manager.cc +++ b/dom/src/dom/animation/animation_manager.cc @@ -396,9 +396,14 @@ void AnimationManager::UpdateAnimations() { auto now = footstone::time::MonotonicallyIncreasingTime(); std::unordered_map> update_node_map; // xcode crash if we change for to loop - for (std::vector>::size_type i = 0; i < active_animations_.size(); ++i) { - UpdateAnimation(active_animations_[i], now, update_node_map); + std::vector> loop_animations = active_animations_; + for (size_t i = 0; i < loop_animations.size(); ++i) { + auto it = std::find(active_animations_.begin(), active_animations_.end(), loop_animations[i]); + if (it != active_animations_.end()) { + UpdateAnimation(loop_animations[i], now, update_node_map); + } } + loop_animations.clear(); std::vector> update_nodes; update_nodes.reserve(update_node_map.size()); for (const auto& [key, value]: update_node_map) { From 2a77ef668678f6aa0a39e421a6c522ad7114edb0 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 8 Nov 2024 11:11:19 +0800 Subject: [PATCH 07/10] fix(android): update pull header LayoutParams in updateLayout --- .../HippyPullHeaderViewController.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java index 886cc3394d1..d07422fffb9 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java @@ -27,6 +27,7 @@ import com.tencent.mtt.hippy.annotation.HippyController; import com.tencent.mtt.hippy.common.HippyArray; import com.tencent.mtt.hippy.uimanager.ControllerManager; +import com.tencent.mtt.hippy.uimanager.ControllerRegistry; import com.tencent.mtt.hippy.uimanager.HippyViewController; import com.tencent.renderer.node.PullHeaderRenderNode; import com.tencent.renderer.node.RenderNode; @@ -102,6 +103,26 @@ public void run() { } } + + @Override + public void updateLayout(int rootId, int id, int x, int y, int width, int height, + ControllerRegistry componentHolder) { + super.updateLayout(rootId, id, x, y, width, height, componentHolder); + View view = componentHolder.getView(rootId, id); + if (view instanceof HippyPullHeaderView && view.getParent() instanceof ViewGroup) { + int w = view.getWidth(); + int h = view.getHeight(); + ViewGroup.LayoutParams lp = view.getLayoutParams(); + if (lp != null) { + LogUtils.d(TAG, "updateLayout: id " + id + ", w " + w + ", h " + h + + ", width " + width + ", height " + height + ", lp.width " + lp.width + ", lp.height " + + lp.height); + lp.width = width; + lp.height = height; + } + } + } + @Override public void dispatchFunction(@NonNull HippyPullHeaderView pullHeaderView, @NonNull String functionName, @NonNull HippyArray params) { From 852c4a5f675fe79f1205434f8370d750053d3175 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 8 Nov 2024 11:29:48 +0800 Subject: [PATCH 08/10] fix(android): avoiding code optimization issues for R8 compile --- modules/android/serialization/build.gradle | 1 + .../hippy/serialization/nio/writer/SafeHeapWriter.java | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/android/serialization/build.gradle b/modules/android/serialization/build.gradle index b82c85d85ff..b1dc05b618c 100644 --- a/modules/android/serialization/build.gradle +++ b/modules/android/serialization/build.gradle @@ -32,4 +32,5 @@ android { dependencies { implementation deps.annotation + implementation project(':hippy-support') } \ No newline at end of file diff --git a/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java b/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java index ebd4f5fb078..b30b18a7237 100644 --- a/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java +++ b/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java @@ -15,6 +15,7 @@ */ package com.tencent.mtt.hippy.serialization.nio.writer; +import com.tencent.mtt.hippy.utils.LogUtils; import java.nio.ByteBuffer; @SuppressWarnings({"unused"}) @@ -73,22 +74,29 @@ public void putDouble(double d) { } @SuppressWarnings("SpellCheckingInspection") + // After upgrading to AGP version 8 or above, R8 compilation will be started. Due to the optimization + // of R8 compilation code, it will affect the logic of the code here, causing encoding and decoding + // failures and white screen problems. Therefore, it is necessary to add some logs in the implementation + // of this function to avoid R8 compilation optimization. @Override public int putVarint(long l) { if (count + 10 > value.length) { enlargeBuffer(count + 10); } - + LogUtils.d("CallFunction", "putVarint l " + l + ", count " + count); long rest = l; int bytes = 0; byte b; do { b = (byte) rest; + LogUtils.d("CallFunction", "putVarint origin b " + b + ", count " + count); b |= 0x80; + LogUtils.d("CallFunction", "putVarint b " + Byte.toUnsignedInt(b) + ", count " + count); value[count++] = b; rest >>>= 7; bytes++; } while (rest != 0); + LogUtils.d("CallFunction", "putVarint bb " + Byte.toUnsignedInt((byte) (b & 0x7f)) + ", bytes " + bytes + ", count " + count); value[count - 1] = (byte) (b & 0x7f); return bytes; } From 166dde2ffaa593785b4a218c74598773a1b74174 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 8 Nov 2024 15:19:33 +0800 Subject: [PATCH 09/10] fix(android): correct some log level --- framework/android/connector/dom/src/main/cpp/src/dom_jni.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/framework/android/connector/dom/src/main/cpp/src/dom_jni.cc b/framework/android/connector/dom/src/main/cpp/src/dom_jni.cc index 0c5021a3b47..750eeeaf0f2 100644 --- a/framework/android/connector/dom/src/main/cpp/src/dom_jni.cc +++ b/framework/android/connector/dom/src/main/cpp/src/dom_jni.cc @@ -163,18 +163,16 @@ jint CreateDomManager(JNIEnv* j_env, jobject j_obj, jint j_group_id, jint j_shar if (share_dom_id > 0) { flag = hippy::global_data_holder.Find(static_cast(share_dom_id), share_dom_manager); } - FOOTSTONE_DLOG(ERROR) << "CreateDomManager flag " << flag << ", dom_id " << dom_id << ", share_dom_id " << share_dom_id; + FOOTSTONE_DLOG(INFO) << "CreateDomManager flag " << flag << ", dom_id " << dom_id<< ", share_dom_id " << share_dom_id << ", group_id " << group_id; if (flag && group_id != kDefaultGroupId) { - FOOTSTONE_DLOG(ERROR) << "CreateDomManager share "; auto dom_manager_object = std::any_cast>(share_dom_manager); auto worker = dom_manager_object->GetWorker(); auto runner = dom_manager_object->GetTaskRunner(); dom_manager->SetTaskRunner(runner); dom_manager->SetWorker(worker); auto count = worker->FetchAndAddReuseCount(); - FOOTSTONE_DLOG(ERROR) << "CreateDomManager worker reuse count " << count << ", dom manager id " << dom_id; + FOOTSTONE_DLOG(INFO) << "CreateDomManager worker reuse count " << count << ", dom manager id " << dom_id; } else { - FOOTSTONE_DLOG(ERROR) << "CreateDomManager create new "; auto worker = std::make_shared(kDomWorkerName, false); auto callback = std::make_shared(j_env, j_obj); worker->BeforeStart([callback]() { From 8dee0581667e2c3952852229b634e1509b3408e7 Mon Sep 17 00:00:00 2001 From: maxli Date: Fri, 8 Nov 2024 16:04:36 +0800 Subject: [PATCH 10/10] fix(android): only debug call R8 avoiding log --- .../nio/writer/SafeHeapWriter.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java b/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java index b30b18a7237..7d08fe8b402 100644 --- a/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java +++ b/modules/android/serialization/src/main/java/com/tencent/mtt/hippy/serialization/nio/writer/SafeHeapWriter.java @@ -83,20 +83,29 @@ public int putVarint(long l) { if (count + 10 > value.length) { enlargeBuffer(count + 10); } - LogUtils.d("CallFunction", "putVarint l " + l + ", count " + count); + if (LogUtils.isDebugMode()) { + LogUtils.d("CallFunction", "putVarint l " + l + ", count " + count); + } long rest = l; int bytes = 0; byte b; do { b = (byte) rest; - LogUtils.d("CallFunction", "putVarint origin b " + b + ", count " + count); + if (LogUtils.isDebugMode()) { + LogUtils.d("CallFunction", "putVarint origin b " + b + ", count " + count); + } b |= 0x80; - LogUtils.d("CallFunction", "putVarint b " + Byte.toUnsignedInt(b) + ", count " + count); + if (LogUtils.isDebugMode()) { + LogUtils.d("CallFunction", "putVarint b " + Byte.toUnsignedInt(b) + ", count " + count); + } value[count++] = b; rest >>>= 7; bytes++; } while (rest != 0); - LogUtils.d("CallFunction", "putVarint bb " + Byte.toUnsignedInt((byte) (b & 0x7f)) + ", bytes " + bytes + ", count " + count); + if (LogUtils.isDebugMode()) { + LogUtils.d("CallFunction", + "putVarint bb " + Byte.toUnsignedInt((byte) (b & 0x7f)) + ", bytes " + bytes + ", count " + count); + } value[count - 1] = (byte) (b & 0x7f); return bytes; }