diff --git a/.github/workflows/pod_spec_lint.yml b/.github/workflows/pod_spec_lint.yml
new file mode 100644
index 00000000000..a169f9dee17
--- /dev/null
+++ b/.github/workflows/pod_spec_lint.yml
@@ -0,0 +1,32 @@
+name: '[pods] pod spec lint'
+
+on:
+ pull_request:
+ branches:
+ - main
+ paths:
+ - 'framework/ios/**'
+ - 'framework/examples/ios-demo/**'
+ - 'driver/js/src/**'
+ - 'driver/js/include/**'
+ - 'dom/include/**'
+ - 'dom/src/**'
+ - 'layout/engine/**'
+ - 'modules/ios/**'
+ - 'modules/footstone/**'
+ - 'modules/vfs/ios/**'
+ - 'modules/vfs/native/**'
+ - 'renderer/native/ios/**'
+ - 'devtools/devtools-backend/**'
+
+jobs:
+ pod_spec_lint:
+ runs-on: macos-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ lfs: true
+ - name: Pod Spec Lint
+ run: |
+ pod spec lint hippy.podspec --allow-warnings --use-libraries --verbose --skip-import-validation
diff --git a/.github/workflows/pod_spec_lint_bypass.yml b/.github/workflows/pod_spec_lint_bypass.yml
new file mode 100644
index 00000000000..4d7b056cba8
--- /dev/null
+++ b/.github/workflows/pod_spec_lint_bypass.yml
@@ -0,0 +1,32 @@
+name: '[pods] pod spec lint'
+
+on:
+ pull_request:
+ branches:
+ - main
+ paths-ignore:
+ - 'framework/ios/**'
+ - 'framework/examples/ios-demo/**'
+ - 'driver/js/src/**'
+ - 'driver/js/include/**'
+ - 'dom/include/**'
+ - 'dom/src/**'
+ - 'layout/engine/**'
+ - 'modules/ios/**'
+ - 'modules/footstone/**'
+ - 'modules/vfs/ios/**'
+ - 'modules/vfs/native/**'
+ - 'renderer/native/ios/**'
+ - 'devtools/devtools-backend/**'
+
+jobs:
+ pod_spec_lint:
+ runs-on: macos-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ lfs: true
+ - name: Pod_Spec_Lint_Bypass
+ run: |
+ echo "No Pod Spec Lint required"
diff --git a/.github/workflows/project_artifact_compare.yml b/.github/workflows/project_artifact_compare.yml
new file mode 100644
index 00000000000..73676e77cf2
--- /dev/null
+++ b/.github/workflows/project_artifact_compare.yml
@@ -0,0 +1,154 @@
+name: "[project] artifact compare"
+
+on:
+ workflow_dispatch:
+ inputs:
+ git_ref_a:
+ description: 'Git Ref A'
+ type: string
+ required: true
+ git_ref_b:
+ description: 'Git Ref B(contrast)'
+ type: string
+ required: false
+ is_compare_for_android:
+ description: 'Compare for Android artifact'
+ type: boolean
+ default: true
+ required: true
+ is_compare_for_ios:
+ description: 'Compare for iOS artifact'
+ type: boolean
+ default: true
+ required: true
+
+jobs:
+ android:
+ if: ${{ github.event.inputs.is_compare_for_android == 'true' }}
+ runs-on: ${{ github.repository == 'Tencent/Hippy' && fromJson('[''self-hosted'', ''linux'']') || 'ubuntu-latest' }}
+ container:
+ image: ghcr.io/tencent/android-release:latest # repository name must be lowercase(${{ github.repository_owner }})
+ strategy:
+ matrix:
+ ref: ${{ fromJSON(format('[''{0}'', ''{1}'']', github.event.inputs.git_ref_a, github.event.inputs.git_ref_b)) }}
+ include:
+ - ref: ${{ github.event.inputs.git_ref_a }}
+ source: ref_a
+ - ref: ${{ github.event.inputs.git_ref_b }}
+ source: ref_b
+ defaults:
+ run:
+ shell: bash
+ outputs:
+ ref_a: ${{ steps.get_size.outputs.ref_a }}
+ ref_b: ${{ steps.get_size.outputs.ref_b }}
+ artifact: Android(android-sdk.aar)
+ steps:
+ - name: Checkout
+ if: ${{ matrix.ref }}
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ matrix.ref }}
+ lfs: true
+ - name: Build
+ if: ${{ matrix.ref }}
+ run: |
+ ./gradlew assembleRelease -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true
+ - name: Size
+ id: get_size
+ run: |
+ if [[ "${{ matrix.ref }}" ]]; then
+ echo "${{ matrix.source }}=$(ls -l ./android/sdk/build/outputs/aar/android-sdk.aar | awk '{print $5}')" >> $GITHUB_OUTPUT
+ else
+ echo "${{ matrix.source }}=-1" >> $GITHUB_OUTPUT
+ fi
+
+ ios:
+ if: ${{ github.event.inputs.is_compare_for_ios == 'true' }}
+ runs-on: macos-latest
+ strategy:
+ matrix:
+ ref: ${{ fromJSON(format('[''{0}'', ''{1}'']', github.event.inputs.git_ref_a, github.event.inputs.git_ref_b)) }}
+ include:
+ - ref: ${{ github.event.inputs.git_ref_a }}
+ source: ref_a
+ - ref: ${{ github.event.inputs.git_ref_b }}
+ source: ref_b
+ outputs:
+ ref_a: ${{ steps.get_size.outputs.ref_a }}
+ ref_b: ${{ steps.get_size.outputs.ref_b }}
+ artifact: iOS(libhippy.a)
+ steps:
+ - name: Checkout
+ if: ${{ matrix.ref }}
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ matrix.ref }}
+ lfs: true
+ - name: Build
+ if: ${{ matrix.ref }}
+ run: |
+ pushd examples/ios-demo
+ pod install
+ popd
+ xcodebuild build \
+ -destination 'generic/platform=iOS' \
+ -project '_Pods.xcodeproj' \
+ -scheme 'hippy' \
+ -configuration 'Release' \
+ CODE_SIGN_IDENTITY="" \
+ CODE_SIGNING_REQUIRED=NO \
+ CODE_SIGNING_ALLOWED=NO
+ - name: Size
+ id: get_size
+ run: |
+ if [[ "${{ matrix.ref }}" ]]; then
+ echo "${{ matrix.source }}=$(ls -l $(xcodebuild -scheme 'hippy' -showBuildSettings | grep -m 1 TARGET_BUILD_DIR | grep -oEi "\/.*")/libhippy.a | awk '{print $5}')" >> $GITHUB_OUTPUT
+ else
+ echo "${{ matrix.source }}=-1" >> $GITHUB_OUTPUT
+ fi
+
+ collector:
+ needs: [ android, ios ]
+ if: ${{ always() && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Summary
+ shell: python
+ run: |
+ from os import getenv
+ from json import loads
+
+ def sizeof_fmt(num):
+ if num == 0:
+ return "0"
+ for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
+ if abs(num) < 1024.0:
+ return f"{num:3.2f}{unit}"
+ num /= 1024.0
+ return f"{num:.1f}Yi"
+
+ def delta(a, b):
+ num = a - b
+ return "$$\color{%s}{%s%s (%s)}$$" % ("red" if num > 0 else "green", "+" if num > 0 else "", sizeof_fmt(num), "%.2f\\\\%%" % abs(num / a * 100))
+
+ json = loads("""${{ toJSON(needs.*.outputs) }}""")
+ with open(getenv("GITHUB_STEP_SUMMARY"), 'w', encoding='utf-8') as file:
+ for result in json:
+ if "artifact" in result:
+ ref_a = int(result["ref_a"])
+ ref_b = int(result["ref_b"])
+ if ref_a > 0 and ref_b > 0:
+ file.write("## %s Artifact Compare\n" % result["artifact"])
+ file.write("| Ref | Size | Delta |\n")
+ file.write("|------|------|-------|\n")
+ file.write("| %s | %s | %s |\n" % ("${{ github.event.inputs.git_ref_a }}", sizeof_fmt(ref_a), delta(ref_a, ref_b)))
+ file.write("| %s | %s | %s |\n" % ("${{ github.event.inputs.git_ref_b }}", sizeof_fmt(ref_b), delta(ref_b, ref_a)))
+ file.write("\n")
+ elif ref_a > 0:
+ ref_a = int(result["ref_a"])
+ file.write("## %s Artifact\n" % result["artifact"])
+ file.write("| Ref | Size |\n")
+ file.write("|------|------|\n")
+ file.write("| %s | %s |\n" % ("${{ github.event.inputs.git_ref_a }}", sizeof_fmt(ref_a)))
+ file.write("\n")
diff --git a/.github/workflows/project_artifact_release.yml b/.github/workflows/project_artifact_release.yml
new file mode 100644
index 00000000000..399aa990cfc
--- /dev/null
+++ b/.github/workflows/project_artifact_release.yml
@@ -0,0 +1,207 @@
+name: '[project] artifact release'
+
+on:
+ workflow_dispatch:
+ inputs:
+ git_ref:
+ description: 'Git Ref'
+ type: string
+ required: true
+ version_name:
+ description: 'Version name'
+ type: string
+ required: true
+ registry_choice:
+ description: 'Registry choice'
+ type: choice
+ required: true
+ default: 'Both'
+ options:
+ - Default
+ - Github
+ - Both
+ is_release_for_android:
+ description: 'Release for Android'
+ type: boolean
+ default: true
+ required: false
+ is_release_for_ios:
+ description: 'Release for iOS'
+ type: boolean
+ default: true
+ required: false
+ is_release_for_js:
+ description: 'Release for JS'
+ type: boolean
+ default: true
+ required: false
+ js_npm_dist_tag_name:
+ description: 'NPM dist tag name to release'
+ type: string
+ required: false
+ is_npm_version_to_latest_tag:
+ description: 'Set current version to npm latest tag'
+ type: boolean
+ default: true
+ required: false
+
+
+jobs:
+ context_in_lowercase:
+ if: github.event.inputs.is_release_for_android == 'true'
+ runs-on: ubuntu-latest
+ outputs:
+ repository_owner: ${{ steps.get_owner.outputs.lowercase }}
+ steps:
+ - name: Get repo owner(in lowercase)
+ id: get_owner
+ uses: ASzc/change-string-case-action@v2
+ with:
+ string: ${{ github.repository_owner }}
+
+ android_release:
+ if: github.event.inputs.is_release_for_android == 'true'
+ needs: context_in_lowercase
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ build_type: [Debug, Release]
+ include:
+ - build_type: Debug
+ artifact_id: hippy-debug
+ - build_type: Release
+ artifact_id: hippy-common
+ container:
+ image: ghcr.io/${{ needs.context_in_lowercase.outputs.repository_owner }}/android-release:latest
+ steps:
+ - name: Checkout (${{ github.event.inputs.git_ref }})
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.inputs.git_ref }}
+ lfs: true
+ - name: ${{ matrix.build_type }} build
+ env:
+ SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }}
+ SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }}
+ SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }}
+ run: |
+ ./gradlew assemble${{ matrix.build_type }} -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true
+ ./gradlew signMavenAarPublication
+ - name: Pre Archive artifacts
+ shell: bash
+ run: |
+ pip3 install -U cos-python-sdk-v5
+ - name: Archive artifacts
+ working-directory: ./android/sdk/build
+ shell: python3 {0}
+ run: |
+ from qcloud_cos import CosConfig
+ from qcloud_cos import CosS3Client
+ from urllib.parse import urlencode
+ import os
+ import tempfile
+ import zipfile
+
+ artifacts = [("outputs/aar/android-sdk.aar", "hippy/android/${{ matrix.artifact_id }}/${{ github.event.inputs.version_name }}/android-sdk.aar")]
+ for path, dirs, files in os.walk("intermediates/merged_native_libs/%s/out/lib" % "${{ matrix.build_type }}".lower()):
+ if files:
+ with zipfile.ZipFile(tempfile.mkstemp()[1], "w", zipfile.ZIP_DEFLATED) as zip_file:
+ for file in files:
+ zip_file.write(os.path.join(path, file), file)
+ artifacts.append((zip_file.filename, "hippy/android/${{ matrix.artifact_id }}/${{ github.event.inputs.version_name }}/symbols/%s.zip" % os.path.basename(path)))
+
+ metadata = {}
+ metadata["ci-name"] = "Github Action"
+ metadata["ci-id"] = "${{ github.run_id }}"
+ metadata["ci-url"] = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ metadata["artifact-author"] = "${{ github.event.sender.login }}"
+ metadata["git-ref"] = "${{ github.event.inputs.git_ref }}"
+
+ config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}")
+ client = CosS3Client(config)
+ for artifact in artifacts:
+ print("Uploading %s" % artifact[0])
+ response = client.upload_file(
+ Bucket="${{ secrets.COS_BUCKET_ARTIFACTS_STORE }}",
+ Key=artifact[1],
+ LocalFilePath=artifact[0],
+ Metadata={"x-cos-tagging": urlencode(metadata)}
+ )
+ print("Archived %s" % artifact[1])
+ - name: Publish to Github Packages
+ if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Github'
+ env:
+ SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }}
+ SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }}
+ SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }}
+ MAVEN_USERNAME: ${{ secrets.GITHUB_ACTOR }}
+ MAVEN_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
+ MAVEN_URL: https://maven.pkg.github.com/${{ github.repository }}
+ run: |
+ ./gradlew publish -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true
+ - name: Publish to OSSRH
+ if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default'
+ env:
+ SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }}
+ SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }}
+ SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }}
+ MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
+ MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
+ run: |
+ ./gradlew publish -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true
+
+ ios_release:
+ if: github.event.inputs.is_release_for_ios == 'true'
+ runs-on: macos-latest
+ steps:
+ - name: Checkout (${{ github.event.inputs.git_ref }})
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.inputs.git_ref }}
+ lfs: true
+ - name: Publish to Cocoapods
+ if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default'
+ env:
+ COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
+ run: |
+ pod trunk push hippy.podspec --allow-warnings --use-libraries --verbose
+
+ js_release:
+ if: github.event.inputs.is_release_for_js == 'true'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout (${{ github.event.inputs.git_ref }})
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.inputs.git_ref }}
+ lfs: true
+ - name: setup-node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ registry-url: https://npm.pkg.github.com
+ cache: 'npm'
+ cache-dependency-path: package-lock.json
+ - name: Install dependencies
+ run: npm ci && lerna bootstrap --no-ci
+ - name: Build packages
+ run: npm run build
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ registry-url: 'https://registry.npmjs.org'
+ - name: Publish to NPM
+ if: github.event.inputs.js_npm_dist_tag_name != null && (github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default')
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ run: |
+ echo "released js_npm_dist_tag_name is '${{ github.event.inputs.js_npm_dist_tag_name }}'"
+ npx lerna publish from-package --ignore-scripts --yes --dist-tag ${{ github.event.inputs.js_npm_dist_tag_name }}
+ - name: Change tag to latest
+ if: github.event.inputs.is_npm_version_to_latest_tag == 'true'
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ run: |
+ npm run release:tag-to-latest ${{ github.event.inputs.version_name }}
+
+
diff --git a/.github/workflows/voltron_build_tests.yml b/.github/workflows/voltron_build_tests.yml
index 268d1650460..3a7d28fb876 100644
--- a/.github/workflows/voltron_build_tests.yml
+++ b/.github/workflows/voltron_build_tests.yml
@@ -91,7 +91,7 @@ jobs:
working-directory: framework/voltron
voltron_ios_flutter_build:
- runs-on: macos-latest
+ runs-on: macos-13
steps:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
@@ -103,3 +103,5 @@ jobs:
run: flutter pub get
- name: Build for iOS
run: flutter build ios --release --no-codesign
+ env:
+ DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer
diff --git a/docs/development/web-integration.md b/docs/development/web-integration.md
index 4d373acddcb..3d77a392597 100644
--- a/docs/development/web-integration.md
+++ b/docs/development/web-integration.md
@@ -1,7 +1,7 @@
# 前端接入
-Hippy 同时支持 React 和 Vue 两种 UI 框架,通过 [@hippy/react](//www.npmjs.com/package/@hippy/react) 和 [@hippy/vue](//www.npmjs.com/package/@hippy/vue) 两个包提供实现。
+Hippy 同时支持 React 和 Vue 两种 UI 框架,通过 [@hippy/react](//www.npmjs.com/package/@hippy/react) 和 [@hippy/vue](//www.npmjs.com/package/@hippy/vue) 及 [@hippy/vue-next](//www.npmjs.com/package/@hippy/vue-next) 三个包提供实现。
# hippy-react
@@ -97,20 +97,20 @@ new Hippy({
// P.S. entryPage需要通过单节点包裹,不能用数组的形式,例如
import React from 'react';
import {
- View,
- Text,
+ View,
+ Text,
} from '@hippy/react';
export default function app() {
- // 入口文件不要使用这种形式,非入口文件可以使用
- return [
- ,
- test test
- ];
- // 修改成通过单节点包裹
- return (
- ,
- test test
- );
+ // 入口文件不要使用这种形式,非入口文件可以使用
+ return [
+ ,
+ test test
+ ];
+ // 修改成通过单节点包裹
+ return (
+ ,
+ test test
+ );
}
```
@@ -121,10 +121,10 @@ export default function app() {
```json
"scripts": {
- "hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js",
- "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js",
- "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js"
- }
+"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js",
+"hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js",
+"hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js"
+}
```
## hippy-react 转 Web
@@ -133,6 +133,8 @@ export default function app() {
# hippy-vue
+>注意:因vue2.x版本将于年底停止更新,建议用户升级至使用vue3.x版本的@hippy/vue-next
+
[[hippy-vue 介绍]](api/hippy-vue/introduction.md) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo)
hippy-vue 相对简单很多,hippy-vue 只是 [Vue](//vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过 [vue-cli](//cli.vuejs.org/) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html),然后加上一些 hippy-vue 的内容就可以直接将网页渲染到终端了。
@@ -284,6 +286,186 @@ setApp(app);
在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。
+```json
+ "scripts": {
+"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js",
+"hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js",
+"hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js"
+},
+```
+
+## 路由
+
+`@hippy/vue-router` 完整支持 vue-router 中的跳转功能,具体请参考 [hippy-vue-router](api/hippy-vue/router.md) 文档。
+
+# hippy-vue-next
+
+[[hippy-vue-next 介绍]](api/hippy-vue/vue3) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo)
+
+hippy-vue-next 是 [Vue](//cn.vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过脚手架 [vue-cli](//github.com/vuejs/vue-cli) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html#vue-create),然后加上一些 hippy-vue-next 的内容就可以直接将网页渲染到终端了。也可以参考我们的范例项目来初始化你的项目。
+>注意这里使用vue-cli创建项目时构建工具要选择webpack,并且Router和Typescript需要勾选,我们的hippy-vue-next默认都是基于Typescript开发的
+
+## 准备 hippy-vue-next 运行时依赖
+
+请使用 `npm i` 安装以下 npm 包,保证运行时正常。
+
+| 包名 | 说明 |
+|---------------|-------------------------------------|
+| @hippy/vue-next | hippy-vue-next 运行时核心 |
+
+## hippy-vue-next 编译时依赖
+
+以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择:
+
+必须的:
+
+| 包名 | 说明 |
+|------------------------------|------------------------------------|
+| @hippy/debug-server-next | Hippy 前终端调试服务 |
+| @hippy/vue-css-loader | hippy-vue-next 的 CSS 文本到 JS 语法树转换 |
+| @hippy/vue-next-style-parser | hippy-vue-next 的样式 parser |
+| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill |
+| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 |
+| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 |
+| webpack | Webpack 打包程序 |
+| webpack-cli | Webpack 命令行 |
+
+可选的:
+
+| 包名 | 说明 |
+|-------------------------------------|-----------------------------------------------------------------------|
+| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 |
+| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 |
+| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 |
+| @hippy/vue-router-next-history | 支持按安卓物理返回键回退路由 |
+| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 |
+| file-loader | 静态文件加载 |
+| url-loader | 静态文件以 Base64 形式加载 |
+| esbuild & esbuild-loader | 开发环境webpack支持使用esbuild构建,性能比babel更好 |
+
+## hippy-vue-next 编译配置
+
+当前 hippy-vue-next 支持 `Webpack 4 或 Webpack 5`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。
+
+### hippy-vue-next 开发调试编译配置
+
+该配置展示了将 Hippy 运行于终端的最小化配置。
+
+| 配置文件 | 说明 |
+|--------------------------------------------------------------------------------------------------------------------------| ---------- |
+| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.dev.js) | 调试用配置 |
+
+### hippy-vue-next 生产环境编译配置
+
+线上包和开发调试用包主要有两个区别:
+
+1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。
+2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。
+
+| 配置文件 | 说明 |
+|-------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------- |
+| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 |
+| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 |
+| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 |
+| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 |
+| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 |
+
+如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。
+
+!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本,而hippy-vue-next是基于vue-next的,因此使用hippy-vue-next iOS版本必须要10及以上。
+
+## hippy-vue-next 入口文件
+
+因为 hippy-vue-next 的启动参数与 web 页面不一样,所以我们需要专门的 [终端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/src/main-native.ts)来加载一些终端上用到的模块,并作为项目的入口文件
+
+```ts
+// 首先导入所需模块
+import {
+ createApp,
+ type HippyApp,
+ EventBus,
+ setScreenSize,
+ BackAndroid,
+} from '@hippy/vue-next';
+
+import App from './app.vue';
+import { createRouter } from './routes';
+import { setGlobalInitProps } from './util';
+
+// 创建 hippy app 实例
+const app: HippyApp = createApp(App, {
+ // hippy native module name
+ appName: 'Demo',
+ iPhone: {
+ // config of statusBar
+ statusBar: {
+ // disable status bar autofill
+ // disabled: true,
+
+ // Status bar background color, if not set, it will use 4282431619, as #40b883, Vue default green
+ // hippy-vue-css-loader/src/compiler/style/color-parser.js
+ backgroundColor: 4283416717,
+
+ // 状态栏背景图,要注意这个会根据容器尺寸拉伸。
+ // backgroundImage: 'https://user-images.githubusercontent.com/12878546/148737148-d0b227cb-69c8-4b21-bf92-739fb0c3f3aa.png',
+ },
+ },
+ // do not print trace info when set to true
+ // silent: true,
+ /**
+ * whether to trim whitespace on text element,
+ * default is true, if set false, it will follow vue-loader compilerOptions whitespace setting
+ */
+ trimWhitespace: true,
+});
+// create router
+const router = createRouter();
+app.use(router);
+
+// init callback
+const initCallback = ({ superProps, rootViewId }) => {
+ setGlobalInitProps({
+ superProps,
+ rootViewId,
+ });
+ /**
+ * Because the memory history of vue-router is now used,
+ * the initial position needs to be pushed manually, otherwise the router will not be ready.
+ * On the browser, it is matched by vue-router according to location.href, and the default push root path '/'
+ */
+ router.push('/');
+
+ // listen android native back press, must before router back press inject
+ BackAndroid.addListener(() => {
+ console.log('backAndroid');
+ // set true interrupts native back
+ return true;
+ });
+
+ // mount first, you can do something before mount
+ app.mount('#root');
+
+ /**
+ * You can also mount the app after the route is ready, However,
+ * it is recommended to mount first, because it can render content on the screen as soon as possible
+ */
+ // router.isReady().then(() => {
+ // // mount app
+ // app.mount('#root');
+ // });
+};
+
+// start hippy app
+app.$start().then(initCallback);
+
+// you can also use callback to start app like @hippy/vue before
+// app.$start(initCallback);
+```
+
+## hippy-vue-next npm 脚本
+
+在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。
+
```json
"scripts": {
"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js",
@@ -294,5 +476,4 @@ setApp(app);
## 路由
-`@hippy/vue-router` 完整支持 vue-router 中的跳转功能,具体请参考 [hippy-vue-router](api/hippy-vue/router.md) 文档。
-
+`@hippy/vue-next` 无需侵入式修改vue-router,直接使用官方 vue-router 即可,如果需要支持安卓物理健回退时路由历史回退,则可以安装@hippy/vue-router-next-history模块。
diff --git a/driver/js/include/driver/performance/performance.h b/driver/js/include/driver/performance/performance.h
index 093a1329d23..971138f507f 100644
--- a/driver/js/include/driver/performance/performance.h
+++ b/driver/js/include/driver/performance/performance.h
@@ -28,6 +28,8 @@
#include "footstone/string_view.h"
#include "driver/performance/performance_entry.h"
#include "driver/performance/performance_resource_timing.h"
+#include "driver/performance/performance_navigation_timing.h"
+#include "driver/performance/performance_paint_timing.h"
namespace hippy {
inline namespace driver {
@@ -54,6 +56,10 @@ class Performance {
return time_origin_;
}
+ std::shared_ptr PerformanceNavigation(const string_view& name);
+ std::shared_ptr PerformancePaint(const PerformancePaintTiming::Type& type);
+ std::shared_ptr PerformanceResource(const string_view& name);
+
void Mark(const string_view& name);
void ClearMarks(const string_view& name);
void ClearMarks();
@@ -67,8 +73,8 @@ class Performance {
void ClearResourceTimings();
std::vector> GetEntries(const PerformanceEntryFilterOptions& options);
std::vector> GetEntries();
- std::shared_ptr GetEntriesByName(const string_view& name);
- std::shared_ptr GetEntriesByName(const string_view& name, PerformanceEntry::Type type);
+ std::vector> GetEntriesByName(const string_view& name);
+ std::vector> GetEntriesByName(const string_view& name, PerformanceEntry::Type type);
std::vector> GetEntriesByType(PerformanceEntry::Type type);
string_view ToJSON();
diff --git a/driver/js/include/driver/performance/performance_entry.h b/driver/js/include/driver/performance/performance_entry.h
index cd1e8612153..182cdeccbbb 100644
--- a/driver/js/include/driver/performance/performance_entry.h
+++ b/driver/js/include/driver/performance/performance_entry.h
@@ -55,6 +55,12 @@ class PerformanceEntry {
start_time_(start_time),
duration_(duration) {}
+ PerformanceEntry(const string_view& name,
+ SubType sub_type,
+ Type type) : name_(name),
+ sub_type_(sub_type),
+ type_(type) {}
+
virtual ~PerformanceEntry() = default;
inline auto GetName() const {
diff --git a/driver/js/include/driver/performance/performance_navigation_timing.h b/driver/js/include/driver/performance/performance_navigation_timing.h
index 618b565c2e1..4db214968f7 100644
--- a/driver/js/include/driver/performance/performance_navigation_timing.h
+++ b/driver/js/include/driver/performance/performance_navigation_timing.h
@@ -33,62 +33,48 @@ inline namespace performance {
class PerformanceNavigationTiming : public PerformanceEntry {
public:
struct BundleInfo {
- string_view bundle_url;
- TimePoint start;
- TimePoint end;
+ string_view url_;
+ TimePoint execute_source_start_;
+ TimePoint execute_source_end_;
};
- PerformanceNavigationTiming(const string_view& name, const TimePoint& start,
- const TimePoint& engine_initialization_start, const TimePoint& engine_initialization_end,
- std::vector bundle_info,
- const TimePoint& load_instance_start, const TimePoint& load_instance_end,
- const TimePoint& first_frame);
+ PerformanceNavigationTiming(const string_view& name);
- inline auto GetEngineInitializationStart() const {
- return engine_initialization_start_;
+#define DEFINE_SET_AND_GET_METHOD(method_name, member_type, member) \
+ void Set##method_name(member_type t) { \
+ member = t; \
+ } \
+ inline auto Get##method_name() const { \
+ return member; \
}
+ DEFINE_SET_AND_GET_METHOD(HippyNativeInitStart, TimePoint, hippy_native_init_start_)
+ DEFINE_SET_AND_GET_METHOD(HippyNativeInitEnd, TimePoint, hippy_native_init_end_)
+ DEFINE_SET_AND_GET_METHOD(HippyJsEngineInitStart, TimePoint, hippy_js_engine_init_start_)
+ DEFINE_SET_AND_GET_METHOD(HippyJsEngineInitEnd, TimePoint, hippy_js_engine_init_end_)
+ DEFINE_SET_AND_GET_METHOD(HippyRunApplicationStart, TimePoint, hippy_run_application_start_)
+ DEFINE_SET_AND_GET_METHOD(HippyRunApplicationEnd, TimePoint, hippy_run_application_end_)
+ DEFINE_SET_AND_GET_METHOD(HippyFirstFrameStart, TimePoint, hippy_first_frame_start_)
+ DEFINE_SET_AND_GET_METHOD(HippyFirstFrameEnd, TimePoint, hippy_first_frame_end_)
+#undef DEFINE_SET_AND_GET_METHOD
- inline auto GetEngineInitializationEnd() const {
- return engine_initialization_end_;
+ inline const std::vector& GetBundleInfoArray() const {
+ return bundle_info_array_;
}
- inline auto GetBundleInfo() const {
- return bundle_info_;
- }
-
- inline auto GetLoadInstanceStart() const {
- return load_instance_start_;
- }
-
- inline auto GetLoadInstanceEnd() const {
- return load_instance_end_;
- }
-
- inline auto GetFirstFrame() const {
- return first_frame_;
- }
+ BundleInfo& BundleInfoOfUrl(const string_view& url);
virtual string_view ToJSON() override;
private:
-// TimePoint dom_complete_;
-// TimePoint dom_content_loaded_event_end_;
-// TimePoint dom_content_loaded_event_start_;
-// TimePoint dom_interactive_;
-// TimePoint load_event_end_;
-// TimePoint load_event_start_;
-// uint32_t redirect_count_;
-// TimePoint request_start_;
-// TimePoint response_start_;
-// string_view type_; // navigate, reload, back_forward or prerender
-// TimePoint unload_event_end_;
-// TimePoint unload_event_start_;
- TimePoint engine_initialization_start_;
- TimePoint engine_initialization_end_;
- std::vector bundle_info_;
- TimePoint load_instance_start_;
- TimePoint load_instance_end_;
- TimePoint first_frame_;
+ TimePoint hippy_native_init_start_;
+ TimePoint hippy_native_init_end_;
+ TimePoint hippy_js_engine_init_start_;
+ TimePoint hippy_js_engine_init_end_;
+ std::vector bundle_info_array_;
+ TimePoint hippy_run_application_start_;
+ TimePoint hippy_run_application_end_;
+ TimePoint hippy_first_frame_start_;
+ TimePoint hippy_first_frame_end_;
};
}
diff --git a/driver/js/include/driver/performance/performance_paint_timing.h b/driver/js/include/driver/performance/performance_paint_timing.h
index f59331f842f..ae9e74e2230 100644
--- a/driver/js/include/driver/performance/performance_paint_timing.h
+++ b/driver/js/include/driver/performance/performance_paint_timing.h
@@ -36,6 +36,7 @@ class PerformancePaintTiming : public PerformanceEntry {
};
PerformancePaintTiming(Type type, const TimePoint& start_time);
+ PerformancePaintTiming(Type type);
virtual string_view ToJSON() override;
diff --git a/driver/js/include/driver/performance/performance_resource_timing.h b/driver/js/include/driver/performance/performance_resource_timing.h
index f36a60cd0cf..33c9d0e7bb8 100644
--- a/driver/js/include/driver/performance/performance_resource_timing.h
+++ b/driver/js/include/driver/performance/performance_resource_timing.h
@@ -31,109 +31,32 @@ inline namespace performance {
class PerformanceResourceTiming: public PerformanceEntry {
public:
enum class InitiatorType {
- AUDIO, BEACON, BODY, CSS, EARLY_HINT, EMBED, FETCH, FRAME, IFRAME, ICON, IMAGE, IMG, INPUT, LINK, NAVIGATION, OBJECT,
+ OTHER, AUDIO, BEACON, BODY, CSS, EARLY_HINT, EMBED, FETCH, FRAME, IFRAME, ICON, IMAGE, IMG, INPUT, LINK, NAVIGATION, OBJECT,
PING, SCRIPT, TRACK, VIDEO, XMLHTTPREQUEST
};
- PerformanceResourceTiming(const string_view& name, TimePoint start_time, TimeDelta duration,
- const InitiatorType& initiator_type, const string_view& next_hop_protocol, TimePoint worker_start,
- TimePoint redirect_start, TimePoint redirect_end, TimePoint fetch_start,
- TimePoint domain_lookup_start, TimePoint domain_lookup_end, TimePoint connect_start,
- TimePoint connect_end, TimePoint secure_connection_start, TimePoint request_start_,
- TimePoint response_start, TimePoint response_end, uint64_t transfer_size,
- uint64_t encoded_body_size, uint64_t decoded_body_size);
+ PerformanceResourceTiming(const string_view& name);
- inline InitiatorType GetInitiatorType() {
- return initiator_type_;
- }
-
- inline string_view GetNextHopProtocol() {
- return next_hop_protocol_;
- }
-
- inline TimePoint GetWorkerStart() {
- return worker_start_;
- }
-
- inline TimePoint GetRedirectStart() {
- return redirect_start_;
- }
-
- inline TimePoint GetRedirectEnd() {
- return redirect_end_;
- }
-
- inline TimePoint GetFetchStart() {
- return fetch_start_;
- }
-
- inline TimePoint GetDomainLookupStart() {
- return domain_lookup_start_;
- }
-
- inline TimePoint GetDomainLookupEnd() {
- return domain_lookup_end_;
- }
-
- inline TimePoint GetConnectStart() {
- return connect_start_;
- }
-
- inline TimePoint GetConnectEnd() {
- return connect_end_;
- }
-
- inline TimePoint GetSecureConnectionStart() {
- return secure_connection_start_;
- }
-
- inline TimePoint GetRequestStart() {
- return request_start_;
- }
-
- inline TimePoint GetResponseStart() {
- return response_start_;
- }
-
- inline TimePoint GetResponseEnd() {
- return response_end_;
- }
-
- inline uint64_t GetTransferSize() {
- return transfer_size_;
- }
-
- inline uint64_t GetEncodedBodySize() {
- return encoded_body_size_;
- }
-
- inline uint64_t GetDecodedBodySize() {
- return decoded_body_size_;
+#define DEFINE_SET_AND_GET_METHOD(method_name, member_type, member) \
+ void Set##method_name(member_type t) { \
+ member = t; \
+ } \
+ inline auto Get##method_name() const { \
+ return member; \
}
+ DEFINE_SET_AND_GET_METHOD(InitiatorType, InitiatorType, initiator_type_)
+ DEFINE_SET_AND_GET_METHOD(LoadSourceStart, TimePoint, load_source_start_)
+ DEFINE_SET_AND_GET_METHOD(LoadSourceEnd, TimePoint, load_source_end_)
+#undef DEFINE_SET_AND_GET_METHOD
virtual string_view ToJSON() override;
static string_view GetInitiatorString(InitiatorType type);
private:
- InitiatorType initiator_type_;
- string_view next_hop_protocol_;
- TimePoint worker_start_;
- TimePoint redirect_start_;
- TimePoint redirect_end_;
- TimePoint fetch_start_;
- TimePoint domain_lookup_start_;
- TimePoint domain_lookup_end_;
- TimePoint connect_start_;
- TimePoint connect_end_;
- TimePoint secure_connection_start_;
- TimePoint request_start_;
- TimePoint response_start_;
- TimePoint response_end_;
- uint64_t transfer_size_;
- uint64_t encoded_body_size_;
- uint64_t decoded_body_size_;
- // std::vector<> server_timing_{};
+ InitiatorType initiator_type_ = InitiatorType::OTHER;
+ TimePoint load_source_start_;
+ TimePoint load_source_end_;
};
}
diff --git a/driver/js/include/driver/scope.h b/driver/js/include/driver/scope.h
index f23e7503acf..55dff530563 100644
--- a/driver/js/include/driver/scope.h
+++ b/driver/js/include/driver/scope.h
@@ -136,6 +136,7 @@ class Scope : public std::enable_shared_from_this {
using Encoding = hippy::napi::Encoding;
using TaskRunner = footstone::runner::TaskRunner;
using Task = footstone::Task;
+ using TimePoint = footstone::TimePoint;
#ifdef ENABLE_INSPECTOR
using DevtoolsDataSource = hippy::devtools::DevtoolsDataSource;
@@ -241,6 +242,7 @@ class Scope : public std::enable_shared_from_this {
uint64_t GetListenerId(const EventListenerInfo& event_listener_info);
void RunJS(const string_view& js,
+ const string_view& uri,
const string_view& name,
bool is_copy = true);
@@ -270,6 +272,22 @@ class Scope : public std::enable_shared_from_this {
inline void SetUriLoader(std::weak_ptr loader) {
loader_ = loader;
+ auto the_loader = loader_.lock();
+ if (the_loader) {
+ the_loader->SetRequestTimePerformanceCallback([WEAK_THIS](const string_view& uri, const TimePoint& start, const TimePoint& end) {
+ DEFINE_AND_CHECK_SELF(Scope)
+ auto runner = self->GetTaskRunner();
+ if (runner) {
+ auto task = [weak_this, uri, start, end]() {
+ DEFINE_AND_CHECK_SELF(Scope)
+ auto entry = self->GetPerformance()->PerformanceResource(uri);
+ entry->SetLoadSourceStart(start);
+ entry->SetLoadSourceEnd(end);
+ };
+ runner->PostTask(std::move(task));
+ }
+ });
+ }
}
inline std::weak_ptr GetUriLoader() { return loader_; }
diff --git a/driver/js/include/driver/vm/js_vm.h b/driver/js/include/driver/vm/js_vm.h
index 07ea1e5b09b..318b029f4ef 100644
--- a/driver/js/include/driver/vm/js_vm.h
+++ b/driver/js/include/driver/vm/js_vm.h
@@ -27,11 +27,12 @@
#include "driver/napi/js_ctx.h"
#include "footstone/logging.h"
+namespace hippy {
#ifdef ENABLE_INSPECTOR
-#include "devtools/devtools_data_source.h"
+namespace devtools {
+class DevtoolsDataSource;
+}
#endif
-
-namespace hippy {
inline namespace driver {
inline namespace vm {
diff --git a/driver/js/src/js_driver_utils.cc b/driver/js/src/js_driver_utils.cc
index 25ef8c837ac..dd42b720484 100644
--- a/driver/js/src/js_driver_utils.cc
+++ b/driver/js/src/js_driver_utils.cc
@@ -320,6 +320,11 @@ bool JsDriverUtils::RunScript(const std::shared_ptr& scope,
<< ", script content empty, uri = " << uri;
return false;
}
+
+ // perfromance start time
+ auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->BundleInfoOfUrl(uri).execute_source_start_ = footstone::TimePoint::SystemNow();
+
#ifdef JS_V8
auto ret = std::static_pointer_cast(scope->GetContext())->RunScript(
script_content, file_name, is_use_code_cache,&code_cache_content, true);
@@ -357,8 +362,12 @@ bool JsDriverUtils::RunScript(const std::shared_ptr& scope,
auto ret = scope->GetContext()->RunScript(script_content, file_name);
#endif
+ // perfromance end time
+ entry->BundleInfoOfUrl(uri).execute_source_end_ = footstone::TimePoint::SystemNow();
+
auto flag = (ret != nullptr);
FOOTSTONE_LOG(INFO) << "runScript end, flag = " << flag;
+
return flag;
}
diff --git a/driver/js/src/modules/contextify_module.cc b/driver/js/src/modules/contextify_module.cc
index 8e4f1e60f49..bcef9834c2a 100644
--- a/driver/js/src/modules/contextify_module.cc
+++ b/driver/js/src/modules/contextify_module.cc
@@ -175,7 +175,7 @@ void ContextifyModule::LoadUntrustedContent(CallbackInfo& info, void* data) {
auto try_catch = CreateTryCatchScope(true, scope->GetContext());
try_catch->SetVerbose(true);
string_view view_code(reinterpret_cast(move_code.c_str()), move_code.length());
- scope->RunJS(view_code, file_name);
+ scope->RunJS(view_code, uri, file_name);
ctx->SetProperty(global_object, cur_dir_key, last_dir_str_obj, hippy::napi::PropertyAttribute::ReadOnly);
if (try_catch->HasCaught()) {
error = try_catch->Exception();
diff --git a/driver/js/src/modules/performance/performance_entry_module.cc b/driver/js/src/modules/performance/performance_entry_module.cc
index 6ba57ee48db..c7175992f12 100644
--- a/driver/js/src/modules/performance/performance_entry_module.cc
+++ b/driver/js/src/modules/performance/performance_entry_module.cc
@@ -63,12 +63,12 @@ std::shared_ptr> RegisterPerformanceEntry(const
return nullptr;
}
- auto entry = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
- if (!entry) {
+ auto entries = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
+ if (entries.empty()) {
exception = context->CreateException("entry not found");
return nullptr;
}
- return entry;
+ return entries.back();
};
return std::make_shared>(std::move(class_template));
}
diff --git a/driver/js/src/modules/performance/performance_frame_timing_module.cc b/driver/js/src/modules/performance/performance_frame_timing_module.cc
index df389365d31..991fb9b9be9 100644
--- a/driver/js/src/modules/performance/performance_frame_timing_module.cc
+++ b/driver/js/src/modules/performance/performance_frame_timing_module.cc
@@ -63,12 +63,12 @@ std::shared_ptr> RegisterPerformanceFrameT
return nullptr;
}
- auto entry = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
- if (!entry) {
+ auto entries = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
+ if (entries.empty()) {
exception = context->CreateException("entry not found");
return nullptr;
}
- return std::static_pointer_cast(entry);
+ return std::static_pointer_cast(entries.back());
};
return std::make_shared>(std::move(class_template));
diff --git a/driver/js/src/modules/performance/performance_module.cc b/driver/js/src/modules/performance/performance_module.cc
index e8f1309a3fd..1dc69cd7f1a 100644
--- a/driver/js/src/modules/performance/performance_module.cc
+++ b/driver/js/src/modules/performance/performance_module.cc
@@ -184,6 +184,7 @@ std::shared_ptr> RegisterPerformance(const std::weak_
exception = context->CreateException("measure startMark not found");
return nullptr;
}
+ return nullptr;
}
string_view end_mark;
flag = context->GetValueString(arguments[2], &end_mark);
@@ -250,11 +251,16 @@ std::shared_ptr> RegisterPerformance(const std::weak_
return nullptr;
}
if (argument_count == 1) {
- auto entry = performance->GetEntriesByName(name);
- auto javascript_class = scope->GetJavascriptClass(PerformanceEntry::GetSubTypeString(entry->GetSubType()));
- std::shared_ptr argv[] = { context->CreateString(entry->GetName()),
- context->CreateNumber(static_cast(entry->GetSubType())) };
- return context->NewInstance(javascript_class, 2, argv, entry.get());
+ auto entries = performance->GetEntriesByName(name);
+ std::shared_ptr instances[entries.size()];
+ for (size_t i = 0; i < entries.size(); ++i) {
+ auto entry = entries[i];
+ auto javascript_class = scope->GetJavascriptClass(PerformanceEntry::GetSubTypeString(entry->GetSubType()));
+ std::shared_ptr argv[] = { context->CreateString(entry->GetName()),
+ context->CreateNumber(static_cast(entry->GetType())) };
+ instances[i] = context->NewInstance(javascript_class, 2, argv, entry.get());
+ }
+ return context->CreateArray(entries.size(), instances);
}
string_view type;
flag = context->GetValueString(arguments[1], &type);
@@ -267,14 +273,16 @@ std::shared_ptr> RegisterPerformance(const std::weak_
exception = context->CreateException("entry_type error");
return nullptr;
}
- auto entry = performance->GetEntriesByName(name, entry_type);
- if (!entry) {
- return nullptr;
+ auto entries = performance->GetEntriesByName(name, entry_type);
+ std::shared_ptr instances[entries.size()];
+ for (size_t i = 0; i < entries.size(); ++i) {
+ auto entry = entries[i];
+ auto javascript_class = scope->GetJavascriptClass(PerformanceEntry::GetSubTypeString(entry->GetSubType()));
+ std::shared_ptr argv[] = { context->CreateString(entry->GetName()),
+ context->CreateNumber(static_cast(entry->GetType())) };
+ instances[i] = context->NewInstance(javascript_class, 2, argv, entry.get());
}
- auto javascript_class = scope->GetJavascriptClass(PerformanceEntry::GetSubTypeString(entry->GetSubType()));
- std::shared_ptr argv[] = { context->CreateString(entry->GetName()),
- context->CreateNumber(static_cast(entry->GetSubType())) };
- return context->NewInstance(javascript_class, 2, argv, entry.get());
+ return context->CreateArray(entries.size(), instances);
};
class_template.functions.emplace_back(std::move(get_entries_by_name_function_define));
@@ -311,7 +319,7 @@ std::shared_ptr> RegisterPerformance(const std::weak_
auto entry = entries[i];
auto javascript_class = scope->GetJavascriptClass(PerformanceEntry::GetSubTypeString(entry->GetSubType()));
std::shared_ptr argv[] = { context->CreateString(entry->GetName()),
- context->CreateNumber(static_cast(entry->GetSubType())) };
+ context->CreateNumber(static_cast(entry->GetType())) };
instances[i] = context->NewInstance(javascript_class, 2, argv, entry.get());
}
return context->CreateArray(entries.size(), instances);
@@ -384,7 +392,7 @@ std::shared_ptr> RegisterPerformance(const std::weak_
auto entry = entries[i];
auto javascript_class = scope->GetJavascriptClass(PerformanceEntry::GetSubTypeString(entry->GetSubType()));
std::shared_ptr argv[] = { context->CreateString(entry->GetName()),
- context->CreateNumber(static_cast(entry->GetSubType())) };
+ context->CreateNumber(static_cast(entry->GetType())) };
instances[i] = context->NewInstance(javascript_class, 2, argv, entry.get());
}
return context->CreateArray(entries.size(), instances);
diff --git a/driver/js/src/modules/performance/performance_navigation_timing_module.cc b/driver/js/src/modules/performance/performance_navigation_timing_module.cc
index 6458f1b36a2..3231d4f7985 100644
--- a/driver/js/src/modules/performance/performance_navigation_timing_module.cc
+++ b/driver/js/src/modules/performance/performance_navigation_timing_module.cc
@@ -33,8 +33,8 @@ inline namespace driver {
inline namespace module {
constexpr char kBundleInfoUrlKey[] = "url";
-constexpr char kBundleInfoStartKey[] = "start";
-constexpr char kBundleInfoEndKey[] = "end";
+constexpr char kBundleInfoStartKey[] = "executeSourceStart";
+constexpr char kBundleInfoEndKey[] = "executeSourceEnd";
std::shared_ptr> RegisterPerformanceNavigationTiming(const std::weak_ptr& weak_scope) {
ClassTemplate class_template;
@@ -67,102 +67,64 @@ std::shared_ptr> RegisterPerformanceN
return nullptr;
}
- auto entry = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
- if (!entry) {
+ auto entries = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
+ if (entries.empty()) {
exception = context->CreateException("entry not found");
return nullptr;
}
- return std::static_pointer_cast(entry);
+ return std::static_pointer_cast(entries.back());
};
- PropertyDefine engine_initialization_start;
- engine_initialization_start.name = "engineInitializationStart";
- engine_initialization_start.getter = [weak_scope](PerformanceNavigationTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetEngineInitializationStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(engine_initialization_start));
+#define ADD_PROPERTY(prop_var, prop_name, get_prop_method) \
+ PropertyDefine prop_var; \
+ prop_var.name = prop_name; \
+ prop_var.getter = [weak_scope](PerformanceNavigationTiming* thiz, \
+ std::shared_ptr& exception) -> std::shared_ptr { \
+ auto scope = weak_scope.lock(); \
+ if (!scope) { \
+ return nullptr; \
+ } \
+ auto context = scope->GetContext(); \
+ return context->CreateNumber(thiz->get_prop_method().ToEpochDelta().ToMillisecondsF()); \
+ }; \
+ class_template.properties.push_back(std::move(prop_var));
- PropertyDefine engine_initialization_end;
- engine_initialization_end.name = "engineInitializationEnd";
- engine_initialization_end.getter = [weak_scope](PerformanceNavigationTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetEngineInitializationEnd().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(engine_initialization_end));
+ ADD_PROPERTY(hippy_native_init_start, "hippyNativeInitStart", GetHippyNativeInitStart)
+ ADD_PROPERTY(hippy_native_init_end, "hippyNativeInitEnd", GetHippyNativeInitEnd)
+ ADD_PROPERTY(hippy_js_engine_init_start, "hippyJsEngineInitStart", GetHippyJsEngineInitStart)
+ ADD_PROPERTY(hippy_js_engine_init_end, "hippyJsEngineInitEnd", GetHippyJsEngineInitEnd)
+ ADD_PROPERTY(hippy_run_application_start, "hippyRunApplicationStart", GetHippyRunApplicationStart)
+ ADD_PROPERTY(hippy_run_application_end, "hippyRunApplicationEnd", GetHippyRunApplicationEnd)
+ ADD_PROPERTY(hippy_first_frame_start, "hippyFirstFrameStart", GetHippyFirstFrameStart)
+ ADD_PROPERTY(hippy_first_frame_end, "hippyFirstFrameEnd", GetHippyFirstFrameEnd)
+#undef ADD_PROPERTY
PropertyDefine bundle_info;
bundle_info.name = "bundleInfo";
bundle_info.getter = [weak_scope](PerformanceNavigationTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
+ std::shared_ptr& exception) -> std::shared_ptr {
auto scope = weak_scope.lock();
- if (scope) {
+ if (!scope) {
return nullptr;
}
auto context = scope->GetContext();
- auto bundle_info = thiz->GetBundleInfo();
- std::shared_ptr array[bundle_info.size()];
- for (const auto& info: bundle_info) {
+ auto bundle_info_array = thiz->GetBundleInfoArray();
+ std::shared_ptr array[bundle_info_array.size()];
+ for (size_t i = 0; i < bundle_info_array.size(); ++i) {
+ auto& info = bundle_info_array[i];
auto object = context->CreateObject();
- context->SetProperty(object, context->CreateString(kBundleInfoUrlKey), context->CreateString(info.bundle_url));
+ context->SetProperty(object, context->CreateString(kBundleInfoUrlKey),
+ context->CreateString(info.url_));
context->SetProperty(object, context->CreateString(kBundleInfoStartKey),
- context->CreateNumber(info.start.ToEpochDelta().ToMillisecondsF()));
+ context->CreateNumber(info.execute_source_start_.ToEpochDelta().ToMillisecondsF()));
context->SetProperty(object, context->CreateString(kBundleInfoEndKey),
- context->CreateNumber(info.end.ToEpochDelta().ToMillisecondsF()));
+ context->CreateNumber(info.execute_source_end_.ToEpochDelta().ToMillisecondsF()));
+ array[i] = object;
}
- return context->CreateArray(bundle_info.size(), array);
+ return context->CreateArray(bundle_info_array.size(), array);
};
class_template.properties.push_back(std::move(bundle_info));
- PropertyDefine load_instance_start;
- load_instance_start.name = "loadInstanceStart";
- load_instance_start.getter = [weak_scope](PerformanceNavigationTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetLoadInstanceStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(load_instance_start));
-
- PropertyDefine load_instance_end;
- load_instance_end.name = "loadInstanceEnd";
- load_instance_end.getter = [weak_scope](PerformanceNavigationTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetLoadInstanceEnd().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(load_instance_end));
-
- PropertyDefine first_frame;
- first_frame.name = "firstFrame";
- first_frame.getter = [weak_scope](PerformanceNavigationTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetFirstFrame().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(first_frame));
-
return std::make_shared>(std::move(class_template));
}
diff --git a/driver/js/src/modules/performance/performance_paint_timing_module.cc b/driver/js/src/modules/performance/performance_paint_timing_module.cc
index c37a596185d..1ad81689616 100644
--- a/driver/js/src/modules/performance/performance_paint_timing_module.cc
+++ b/driver/js/src/modules/performance/performance_paint_timing_module.cc
@@ -61,12 +61,12 @@ std::shared_ptr> RegisterPerformancePaintT
return nullptr;
}
- auto entry = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
- if (!entry) {
+ auto entries = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
+ if (entries.empty()) {
exception = context->CreateException("entry not found");
return nullptr;
}
- return std::static_pointer_cast(entry);
+ return std::static_pointer_cast(entries.back());
};
return std::make_shared>(std::move(class_template));
diff --git a/driver/js/src/modules/performance/performance_resource_timing_module.cc b/driver/js/src/modules/performance/performance_resource_timing_module.cc
index b401950f899..394b417d2cc 100644
--- a/driver/js/src/modules/performance/performance_resource_timing_module.cc
+++ b/driver/js/src/modules/performance/performance_resource_timing_module.cc
@@ -64,12 +64,12 @@ std::shared_ptr> RegisterPerformanceRes
return nullptr;
}
- auto entry = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
- if (!entry) {
+ auto entries = scope->GetPerformance()->GetEntriesByName(name, static_cast(type));
+ if (entries.empty()) {
exception = context->CreateException("entry not found");
return nullptr;
}
- return std::static_pointer_cast(entry);
+ return std::static_pointer_cast(entries.back());
};
PropertyDefine initiator_type;
@@ -77,7 +77,7 @@ std::shared_ptr> RegisterPerformanceRes
initiator_type.getter = [weak_scope](PerformanceResourceTiming* thiz,
std::shared_ptr& exception) -> std::shared_ptr {
auto scope = weak_scope.lock();
- if (scope) {
+ if (!scope) {
return nullptr;
}
auto context = scope->GetContext();
@@ -85,200 +85,23 @@ std::shared_ptr> RegisterPerformanceRes
};
class_template.properties.push_back(std::move(initiator_type));
- PropertyDefine next_hop_protocol;
- next_hop_protocol.name = "nextHopProtocol";
- next_hop_protocol.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateString(thiz->GetNextHopProtocol());
- };
- class_template.properties.push_back(std::move(next_hop_protocol));
-
- PropertyDefine redirect_start;
- redirect_start.name = "redirectStart";
- redirect_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetRedirectStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(redirect_start));
-
- PropertyDefine redirect_end;
- redirect_end.name = "redirectEnd";
- redirect_end.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetRedirectEnd().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(redirect_end));
-
- PropertyDefine fetch_start;
- fetch_start.name = "fetchStart";
- fetch_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetFetchStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(fetch_start));
-
- PropertyDefine domain_lookup_start;
- domain_lookup_start.name = "domainLookupStart";
- domain_lookup_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetDomainLookupStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(domain_lookup_start));
-
- PropertyDefine domain_lookup_end;
- domain_lookup_end.name = "domainLookupEnd";
- domain_lookup_end.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetDomainLookupEnd().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(domain_lookup_end));
-
- PropertyDefine connect_start;
- connect_start.name = "connectStart";
- connect_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetConnectStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(connect_start));
-
- PropertyDefine connect_end;
- connect_end.name = "connectEnd";
- connect_end.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetConnectEnd().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(connect_end));
-
- PropertyDefine secure_connection_start;
- secure_connection_start.name = "secureConnectionStart";
- secure_connection_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetSecureConnectionStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(secure_connection_start));
-
- PropertyDefine request_start;
- request_start.name = "requestStart";
- request_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetRequestStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(request_start));
-
- PropertyDefine response_start;
- response_start.name = "responseStart";
- response_start.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetResponseStart().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(response_start));
-
- PropertyDefine response_end;
- response_end.name = "responseEnd";
- response_end.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(thiz->GetResponseEnd().ToEpochDelta().ToMillisecondsF());
- };
- class_template.properties.push_back(std::move(response_end));
-
- PropertyDefine transfer_size;
- transfer_size.name = "transferSize";
- transfer_size.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(footstone::checked_numeric_cast(thiz->GetTransferSize()));
- };
- class_template.properties.push_back(std::move(transfer_size));
-
- PropertyDefine encoded_body_size;
- encoded_body_size.name = "encodedBodySize";
- encoded_body_size.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(footstone::checked_numeric_cast(thiz->GetEncodedBodySize()));
- };
- class_template.properties.push_back(std::move(encoded_body_size));
-
- PropertyDefine decoded_body_size;
- decoded_body_size.name = "decodedBodySize";
- decoded_body_size.getter = [weak_scope](PerformanceResourceTiming* thiz,
- std::shared_ptr& exception) -> std::shared_ptr {
- auto scope = weak_scope.lock();
- if (scope) {
- return nullptr;
- }
- auto context = scope->GetContext();
- return context->CreateNumber(footstone::checked_numeric_cast(thiz->GetDecodedBodySize()));
- };
- class_template.properties.push_back(std::move(decoded_body_size));
+#define ADD_PROPERTY(prop_var, prop_name, get_prop_method) \
+ PropertyDefine prop_var; \
+ prop_var.name = prop_name; \
+ prop_var.getter = [weak_scope](PerformanceResourceTiming* thiz, \
+ std::shared_ptr& exception) -> std::shared_ptr { \
+ auto scope = weak_scope.lock(); \
+ if (!scope) { \
+ return nullptr; \
+ } \
+ auto context = scope->GetContext(); \
+ return context->CreateNumber(thiz->get_prop_method().ToEpochDelta().ToMillisecondsF()); \
+ }; \
+ class_template.properties.push_back(std::move(prop_var));
+
+ ADD_PROPERTY(load_source_start, "loadSourceStart", GetLoadSourceStart)
+ ADD_PROPERTY(load_source_end, "loadSourceEnd", GetLoadSourceEnd)
+#undef ADD_PROPERTY
return std::make_shared>(std::move(class_template));
}
diff --git a/driver/js/src/napi/jsc/jsc_ctx.cc b/driver/js/src/napi/jsc/jsc_ctx.cc
index 3855538fb21..0c79151d32e 100644
--- a/driver/js/src/napi/jsc/jsc_ctx.cc
+++ b/driver/js/src/napi/jsc/jsc_ctx.cc
@@ -90,7 +90,7 @@ JSValueRef InvokeJsCallback(JSContextRef ctx,
JSObjectRef global_object = JSContextGetGlobalObject(ctx);
auto global_external_data = JSObjectGetPrivate(global_object);
cb_info.SetSlot(global_external_data);
- auto context = const_cast(ctx);
+ auto context = JSContextGetGlobalContext(ctx);
cb_info.SetReceiver(std::make_shared(context, object));
if (object != global_object) {
auto object_private_data = JSObjectGetPrivate(object);
@@ -141,7 +141,7 @@ JSObjectRef InvokeConstructorCallback(JSContextRef ctx,
JSObjectRef global_obj = JSContextGetGlobalObject(ctx);
auto global_external_data = JSObjectGetPrivate(global_obj);
cb_info.SetSlot(global_external_data);
- auto context = const_cast(ctx);
+ auto context = JSContextGetGlobalContext(ctx);
auto proto = std::static_pointer_cast(constructor_data->prototype)->value_;
JSObjectSetPrototype(ctx, instance, proto);
cb_info.SetReceiver(std::make_shared(context, instance));
@@ -209,7 +209,7 @@ static JSValueRef JSObjectGetPropertyCallback(JSContextRef ctx,
JSValueRef *exception_ref) {
auto data = JSObjectGetPrivate(object);
- auto context = const_cast(ctx);
+ auto context = JSContextGetGlobalContext(ctx);
auto constructor_data = reinterpret_cast(data);
auto function_wrapper = reinterpret_cast(constructor_data->function_wrapper);
auto js_cb = function_wrapper->callback;
diff --git a/driver/js/src/performance/performance.cc b/driver/js/src/performance/performance.cc
index 02f607f8be0..ffc0d04d6fd 100644
--- a/driver/js/src/performance/performance.cc
+++ b/driver/js/src/performance/performance.cc
@@ -28,6 +28,7 @@
#include "driver/performance/performance_measure.h"
#include "footstone/check.h"
#include "footstone/logging.h"
+#include "footstone/string_view_utils.h"
namespace hippy {
inline namespace driver {
@@ -39,6 +40,61 @@ Performance::Performance(): resource_timing_current_buffer_size_(0),
resource_timing_max_buffer_size_(kMaxSize),
time_origin_(TimePoint::Now()) {}
+std::shared_ptr Performance::PerformanceNavigation(const string_view& name) {
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
+ if (name_iterator != name_map_.end()) {
+ for (auto& entry : name_iterator->second) {
+ if (entry->GetType() == PerformanceEntry::Type::kNavigation) {
+ return std::static_pointer_cast(entry);
+ }
+ }
+ }
+
+ auto entry = std::make_shared(name);
+ if (InsertEntry(entry)) {
+ return entry;
+ }
+ return nullptr;
+}
+
+std::shared_ptr Performance::PerformancePaint(const PerformancePaintTiming::Type& type) {
+ auto name = (type == PerformancePaintTiming::Type::kFirstPaint ? "first-paint" : "first-contentful-paint");
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
+ if (name_iterator != name_map_.end()) {
+ for (auto& entry : name_iterator->second) {
+ if (entry->GetType() == PerformanceEntry::Type::kPaint) {
+ return std::static_pointer_cast(entry);
+ }
+ }
+ }
+
+ auto entry = std::make_shared(type);
+ if (InsertEntry(entry)) {
+ return entry;
+ }
+ return nullptr;
+}
+
+std::shared_ptr Performance::PerformanceResource(const string_view& name) {
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
+ if (name_iterator != name_map_.end()) {
+ for (auto& entry : name_iterator->second) {
+ if (entry->GetType() == PerformanceEntry::Type::kResource) {
+ return std::static_pointer_cast(entry);
+ }
+ }
+ }
+
+ auto entry = std::make_shared(name);
+ if (InsertEntry(entry)) {
+ return entry;
+ }
+ return nullptr;
+}
+
void Performance::Mark(const Performance::string_view& name) {
auto entry = std::make_shared(
name, TimePoint::Now(), nullptr);
@@ -61,24 +117,36 @@ bool Performance::Measure(const Performance::string_view &name) {
bool Performance::Measure(const Performance::string_view &name,
const Performance::string_view &start_mark) {
- auto start_mark_entry = GetEntriesByName(start_mark, PerformanceEntry::Type::kMark);
+ auto entries = GetEntriesByName(start_mark, PerformanceEntry::Type::kMark);
+ if (entries.empty()) {
+ return false;
+ }
+ auto start_mark_entry = entries.back();
if (!start_mark_entry) {
return false;
}
- auto entry = std::make_shared(
- name, PerformanceEntry::SubType::kPerformanceMeasure, PerformanceEntry::Type::kMeasure, start_mark_entry->GetStartTime(),
- Now() - start_mark_entry->GetStartTime());
+ auto entry = std::make_shared(
+ name, start_mark_entry->GetStartTime(),
+ Now() - start_mark_entry->GetStartTime(), nullptr);
return InsertEntry(entry);
}
bool Performance::Measure(const Performance::string_view& name,
const Performance::string_view& start_mark,
const Performance::string_view& end_mark) {
- auto start_mark_entry = GetEntriesByName(start_mark, PerformanceEntry::Type::kMark);
+ auto start_entries = GetEntriesByName(start_mark, PerformanceEntry::Type::kMark);
+ if (start_entries.empty()) {
+ return false;
+ }
+ auto start_mark_entry = start_entries.back();
if (!start_mark_entry) {
return false;
}
- auto end_mark_entry = GetEntriesByName(end_mark, PerformanceEntry::Type::kMark);
+ auto end_entries = GetEntriesByName(end_mark, PerformanceEntry::Type::kMark);
+ if (end_entries.empty()) {
+ return false;
+ }
+ auto end_mark_entry = end_entries.back();
if (!end_mark_entry) {
return false;
}
@@ -87,15 +155,19 @@ bool Performance::Measure(const Performance::string_view& name,
}
bool Performance::InsertEntry(const std::shared_ptr& entry) {
- if (entry->GetType() == PerformanceEntry::Type::kResource && resource_timing_current_buffer_size_ >= resource_timing_max_buffer_size_) {
- return false;
+ if (entry->GetType() == PerformanceEntry::Type::kResource) {
+ if (resource_timing_current_buffer_size_ >= resource_timing_max_buffer_size_) {
+ return false;
+ }
+ ++resource_timing_current_buffer_size_;
}
auto name = entry->GetName();
- auto name_iterator = name_map_.find(name);
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
if (name_iterator == name_map_.end()) {
- name_map_[name] = { entry };
+ name_map_[u16n] = { entry };
} else {
- name_map_[name].push_back(entry);
+ name_map_[u16n].push_back(entry);
}
auto type = entry->GetType();
auto type_iterator = type_map_.find(type);
@@ -111,35 +183,37 @@ bool Performance::Measure(const Performance::string_view& name,
const std::shared_ptr& start_mark,
const std::shared_ptr& end_mark) {
FOOTSTONE_CHECK(start_mark && end_mark);
- auto entry = std::make_shared(
- name, PerformanceEntry::SubType::kPerformanceMeasure, PerformanceEntry::Type::kMeasure, start_mark->GetStartTime(),
- end_mark->GetStartTime() - end_mark->GetStartTime());
+ auto entry = std::make_shared(
+ name, start_mark->GetStartTime(),
+ end_mark->GetStartTime() - start_mark->GetStartTime(), nullptr);
return InsertEntry(entry);
}
-std::shared_ptr Performance::GetEntriesByName(const Performance::string_view& name) {
- auto iterator = name_map_.find(name);
+std::vector> Performance::GetEntriesByName(const Performance::string_view& name) {
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto iterator = name_map_.find(u16n);
if (iterator == name_map_.end()) {
- return nullptr;
+ return {};
}
- return iterator->second.back();
+ return iterator->second;
}
-std::shared_ptr Performance::GetEntriesByName(const Performance::string_view& name,
- PerformanceEntry::Type type) {
- auto iterator = name_map_.find(name);
+std::vector> Performance::GetEntriesByName(const Performance::string_view& name,
+ PerformanceEntry::Type type) {
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto iterator = name_map_.find(u16n);
if (iterator == name_map_.end()) {
- return nullptr;
+ return {};
}
auto array = iterator->second;
- auto array_iterator = std::find_if(array.rbegin(), array.rend(),
+ auto array_iterator = std::find_if(array.begin(), array.end(),
[type](const std::shared_ptr& entry) {
return entry->GetType() == type;
});
- if (array_iterator == array.rend()) {
- return nullptr;
+ if (array_iterator == array.end()) {
+ return {};
}
- return *array_iterator;
+ return std::vector>(array_iterator, array.end());
}
std::vector> Performance::GetEntriesByType(PerformanceEntry::Type type) {
@@ -151,7 +225,8 @@ std::vector> Performance::GetEntriesByType(Per
}
void Performance::RemoveEntry(const Performance::string_view& name) {
- auto name_iterator = name_map_.find(name);
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
if (name_iterator == name_map_.end()) {
return;
}
@@ -160,8 +235,9 @@ void Performance::RemoveEntry(const Performance::string_view& name) {
FOOTSTONE_CHECK(type_iterator != type_map_.end());
auto array = type_iterator->second;
auto erase_iterator = std::remove_if(array.begin(), array.end(),
- [name](const std::shared_ptr& item) {
- return item->GetName() == name;
+ [u16n](const std::shared_ptr& item) {
+ auto u16n2 = footstone::StringViewUtils::ConvertEncoding(item->GetName(), string_view::Encoding::Utf16);
+ return u16n2 == u16n;
});
if (entry->GetType() == PerformanceEntry::Type::kResource) {
auto count = std::distance(erase_iterator, array.end());
@@ -179,7 +255,8 @@ void Performance::RemoveEntry(PerformanceEntry::Type type) {
return;
}
for (const auto& entry: type_iterator->second) {
- auto name_iterator = name_map_.find(entry->GetName());
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(entry->GetName(), string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
FOOTSTONE_CHECK(name_iterator != name_map_.end());
auto array = name_iterator->second;
array.erase(std::remove_if(array.begin(), array.end(),
@@ -194,14 +271,15 @@ void Performance::RemoveEntry(PerformanceEntry::Type type) {
}
void Performance::RemoveEntry(const Performance::string_view& name, PerformanceEntry::Type type) {
- auto name_iterator = name_map_.find(name);
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(name, string_view::Encoding::Utf16);
+ auto name_iterator = name_map_.find(u16n);
if (name_iterator == name_map_.end()) {
return;
}
auto name_array = name_iterator->second;
name_array.erase(std::remove_if(name_array.begin(), name_array.end(),
- [&type_map = type_map_, &size = resource_timing_current_buffer_size_, type](
+ [&type_map = type_map_, &size = resource_timing_current_buffer_size_, u16n, type](
const std::shared_ptr& entry) {
if (entry->GetType() != type) {
return false;
@@ -210,8 +288,9 @@ void Performance::RemoveEntry(const Performance::string_view& name, PerformanceE
FOOTSTONE_CHECK(type_iterator != type_map.end());
auto type_array = type_iterator->second;
auto erase_iterator = std::remove_if(type_array.begin(), type_array.end(),
- [name = entry->GetName()](const std::shared_ptr& item) {
- return item->GetName() == name;
+ [u16n](const std::shared_ptr& item) {
+ auto u16n2 = footstone::StringViewUtils::ConvertEncoding(item->GetName(), string_view::Encoding::Utf16);
+ return u16n2 == u16n;
});
if (type == PerformanceEntry::Type::kResource) {
auto count = std::distance(erase_iterator, type_array.end());
@@ -243,15 +322,15 @@ std::vector> Performance::GetEntries() {
std::vector> ret;
for (auto [ key, value ]: type_map_) {
if (!ret.empty()) {
- auto size = ret.size() + value.size();
- ret.resize(size);
- std::merge(ret.begin(), ret.end(), value.begin(), value.end(), ret.begin(),
+ std::vector> merged_ret;
+ std::merge(ret.begin(), ret.end(), value.begin(), value.end(), std::back_inserter(merged_ret),
[](const std::shared_ptr& lhs, const std::shared_ptr& rhs) {
if (lhs && rhs) {
return lhs->GetStartTime() < rhs->GetStartTime();
}
return true;
});
+ ret = merged_ret;
} else {
ret = value;
}
diff --git a/driver/js/src/performance/performance_navigation_timing.cc b/driver/js/src/performance/performance_navigation_timing.cc
index 0dd9f1232eb..f2584cddeac 100644
--- a/driver/js/src/performance/performance_navigation_timing.cc
+++ b/driver/js/src/performance/performance_navigation_timing.cc
@@ -21,27 +21,35 @@
*/
#include "driver/performance/performance_navigation_timing.h"
-
+#include "footstone/string_view_utils.h"
#include
namespace hippy {
inline namespace driver {
inline namespace performance {
-PerformanceNavigationTiming::PerformanceNavigationTiming(
- const string_view& name, const TimePoint& start,
- const TimePoint& engine_initialization_start, const TimePoint& engine_initialization_end,
- std::vector bundle_info,
- const TimePoint& load_instance_start, const TimePoint& load_instance_end,
- const TimePoint& first_frame): PerformanceEntry(
- name, SubType::kPerformanceNavigationTiming, Type::kNavigation, start, TimePoint::Now() - start),
- engine_initialization_start_(engine_initialization_start), engine_initialization_end_(engine_initialization_end),
- bundle_info_(std::move(bundle_info)), load_instance_start_(load_instance_start), load_instance_end_(load_instance_end) {}
+PerformanceNavigationTiming::PerformanceNavigationTiming(const string_view& name)
+: PerformanceEntry(name, SubType::kPerformanceNavigationTiming, Type::kNavigation) {}
PerformanceEntry::string_view PerformanceNavigationTiming::ToJSON() {
return PerformanceEntry::ToJSON();
}
+PerformanceNavigationTiming::BundleInfo& PerformanceNavigationTiming::BundleInfoOfUrl(const string_view& url) {
+ auto u16n = footstone::StringViewUtils::ConvertEncoding(url, string_view::Encoding::Utf16);
+ for (auto& info : bundle_info_array_) {
+ auto u16n2 = footstone::StringViewUtils::ConvertEncoding(info.url_, string_view::Encoding::Utf16);
+ if (u16n2 == u16n) {
+ return info;
+ }
+ }
+
+ PerformanceNavigationTiming::BundleInfo info;
+ info.url_ = url;
+ bundle_info_array_.emplace_back(info);
+ return bundle_info_array_.back();
+}
+
}
}
}
diff --git a/driver/js/src/performance/performance_paint_timing.cc b/driver/js/src/performance/performance_paint_timing.cc
index 249273f63a0..479d5338c67 100644
--- a/driver/js/src/performance/performance_paint_timing.cc
+++ b/driver/js/src/performance/performance_paint_timing.cc
@@ -29,7 +29,7 @@ inline namespace performance {
PerformancePaintTiming::PerformancePaintTiming(PerformancePaintTiming::Type type,
const TimePoint& start_time)
: PerformanceEntry(
- type == Type::kFirstContentfulPaint ? "first-paint" : "first-contentful-paint",
+ type == Type::kFirstPaint ? "first-paint" : "first-contentful-paint",
SubType::kPerformancePaintTiming,
PerformanceEntry::Type::kPaint,
start_time,
@@ -37,6 +37,12 @@ PerformancePaintTiming::PerformancePaintTiming(PerformancePaintTiming::Type type
}
+PerformancePaintTiming::PerformancePaintTiming(Type type)
+: PerformanceEntry(
+ type == Type::kFirstPaint ? "first-paint" : "first-contentful-paint",
+ SubType::kPerformancePaintTiming,
+ PerformanceEntry::Type::kPaint) {}
+
PerformanceEntry::string_view PerformancePaintTiming::ToJSON() {
return PerformanceEntry::ToJSON();
}
diff --git a/driver/js/src/performance/performance_resource_timing.cc b/driver/js/src/performance/performance_resource_timing.cc
index 39f196e48b4..5572d94ea7e 100644
--- a/driver/js/src/performance/performance_resource_timing.cc
+++ b/driver/js/src/performance/performance_resource_timing.cc
@@ -33,45 +33,8 @@ namespace hippy {
inline namespace driver {
inline namespace performance {
-PerformanceResourceTiming::PerformanceResourceTiming(
- const string_view& name,
- TimePoint start_time,
- TimeDelta duration,
- const InitiatorType& initiator_type,
- const string_view& next_hop_protocol,
- TimePoint worker_start,
- TimePoint redirect_start,
- TimePoint redirect_end,
- TimePoint fetch_start,
- TimePoint domain_lookup_start,
- TimePoint domain_lookup_end,
- TimePoint connect_start,
- TimePoint connect_end,
- TimePoint secure_connection_start,
- TimePoint request_start,
- TimePoint response_start,
- TimePoint response_end,
- uint64_t transfer_size,
- uint64_t encoded_body_size,
- uint64_t decoded_body_size) :
- PerformanceEntry(name, SubType::kPerformanceResourceTiming, Type::kResource, start_time, duration),
- initiator_type_(initiator_type),
- next_hop_protocol_(next_hop_protocol),
- worker_start_(worker_start),
- redirect_start_(redirect_start),
- redirect_end_(redirect_end),
- fetch_start_(fetch_start),
- domain_lookup_start_(domain_lookup_start),
- domain_lookup_end_(domain_lookup_end),
- connect_start_(connect_start),
- connect_end_(connect_end),
- secure_connection_start_(secure_connection_start),
- request_start_(request_start),
- response_start_(response_start),
- response_end_(response_end),
- transfer_size_(transfer_size),
- encoded_body_size_(encoded_body_size),
- decoded_body_size_(decoded_body_size) {}
+PerformanceResourceTiming::PerformanceResourceTiming(const string_view& name)
+: PerformanceEntry(name, SubType::kPerformanceResourceTiming, Type::kResource) {}
string_view PerformanceResourceTiming::ToJSON() {
return "";
@@ -79,7 +42,10 @@ string_view PerformanceResourceTiming::ToJSON() {
string_view PerformanceResourceTiming::GetInitiatorString(InitiatorType type) {
switch (type) {
- case InitiatorType::AUDIO:{
+ case InitiatorType::OTHER: {
+ return "other";
+ }
+ case InitiatorType::AUDIO: {
return "audio";
}
case InitiatorType::BEACON: {
diff --git a/driver/js/src/scope.cc b/driver/js/src/scope.cc
index d066e1019ba..86f82d28e69 100644
--- a/driver/js/src/scope.cc
+++ b/driver/js/src/scope.cc
@@ -481,10 +481,16 @@ uint64_t Scope::GetListenerId(const EventListenerInfo& event_listener_info) {
}
void Scope::RunJS(const string_view& data,
+ const string_view& uri,
const string_view& name,
bool is_copy) {
std::weak_ptr weak_context = context_;
- auto callback = [data, name, is_copy, weak_context] {
+ auto callback = [WEAK_THIS, data, uri, name, is_copy, weak_context] {
+ DEFINE_AND_CHECK_SELF(Scope)
+ // perfromance start time
+ auto entry = self->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->BundleInfoOfUrl(uri).execute_source_start_ = footstone::TimePoint::SystemNow();
+
#ifdef JS_V8
auto context = std::static_pointer_cast(weak_context.lock());
if (context) {
@@ -496,6 +502,9 @@ void Scope::RunJS(const string_view& data,
context->RunScript(data, name);
}
#endif
+
+ // perfromance end time
+ entry->BundleInfoOfUrl(uri).execute_source_end_ = footstone::TimePoint::SystemNow();
};
auto runner = GetTaskRunner();
@@ -510,10 +519,16 @@ void Scope::LoadInstance(const std::shared_ptr& value) {
std::weak_ptr weak_context = context_;
#ifdef ENABLE_INSPECTOR
std::weak_ptr weak_data_source = devtools_data_source_;
- auto cb = [weak_context, value, weak_data_source]() mutable {
+ auto cb = [WEAK_THIS, weak_context, value, weak_data_source]() mutable {
#else
- auto cb = [weak_context, value]() mutable {
+ auto cb = [WEAK_THIS, weak_context, value]() mutable {
#endif
+ DEFINE_AND_CHECK_SELF(Scope)
+ // perfromance start time
+ auto entry = self->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->SetHippyFirstFrameStart(footstone::TimePoint::SystemNow());
+ entry->SetHippyRunApplicationStart(footstone::TimePoint::SystemNow());
+
std::shared_ptr context = weak_context.lock();
if (context) {
auto global_object = context->GetGlobalObject();
@@ -544,6 +559,9 @@ void Scope::LoadInstance(const std::shared_ptr& value) {
context->ThrowException("Application entry not found");
}
}
+
+ // perfromance end time
+ entry->SetHippyRunApplicationEnd(footstone::TimePoint::SystemNow());
};
auto runner = GetTaskRunner();
if (footstone::Worker::IsTaskRunning() && runner == footstone::runner::TaskRunner::GetCurrentTaskRunner()) {
diff --git a/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h b/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h
index b3f8e22aee0..522e7d28632 100644
--- a/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h
+++ b/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h
@@ -84,6 +84,12 @@ void SetDomManager(JNIEnv* j_env,
jint j_runtime_id,
jint j_dom_manager_id);
+void OnNativeInitEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong startTime, jlong endTime);
+
+void OnFirstFrameEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time);
+
+void OnResourceLoadEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jstring j_uri, jlong j_start_time, jlong j_end_time);
+
}
}
}
diff --git a/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc b/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc
index bdaf428d088..c7ddb148e6e 100644
--- a/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc
+++ b/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc
@@ -102,6 +102,21 @@ REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp)
"(II)V",
SetDomManager)
+REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp)
+ "onNativeInitEnd",
+ "(IJJ)V",
+ OnNativeInitEnd)
+
+REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp)
+ "onFirstFrameEnd",
+ "(IJ)V",
+ OnFirstFrameEnd)
+
+REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp)
+ "onResourceLoadEnd",
+ "(ILjava/lang/String;JJ)V",
+ OnResourceLoadEnd)
+
using string_view = footstone::stringview::string_view;
using u8string = footstone::string_view::u8string;
using StringViewUtils = footstone::stringview::StringViewUtils;
@@ -134,6 +149,60 @@ std::shared_ptr GetScope(jint j_scope_id) {
return std::any_cast>(scope_object);
}
+void OnNativeInitEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong startTime, jlong endTime) {
+ auto scope = GetScope(j_scope_id);
+ auto runner = scope->GetEngine().lock()->GetJsTaskRunner();
+ if (runner) {
+ std::weak_ptr weak_scope = scope;
+ auto task = [weak_scope, startTime, endTime]() {
+ auto scope = weak_scope.lock();
+ if (scope) {
+ auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->SetHippyNativeInitStart(footstone::TimePoint::FromEpochDelta(footstone::TimeDelta::FromMilliseconds(startTime)));
+ entry->SetHippyNativeInitEnd(footstone::TimePoint::FromEpochDelta(footstone::TimeDelta::FromMilliseconds(endTime)));
+ }
+ };
+ runner->PostTask(std::move(task));
+ }
+}
+
+void OnFirstFrameEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time) {
+ auto scope = GetScope(j_scope_id);
+ auto runner = scope->GetEngine().lock()->GetJsTaskRunner();
+ if (runner) {
+ std::weak_ptr weak_scope = scope;
+ auto task = [weak_scope, time]() {
+ auto scope = weak_scope.lock();
+ if (scope) {
+ auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->SetHippyFirstFrameEnd(footstone::TimePoint::FromEpochDelta(footstone::TimeDelta::FromMilliseconds(time)));
+ }
+ };
+ runner->PostTask(std::move(task));
+ }
+}
+
+void OnResourceLoadEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jstring j_uri, jlong j_start_time, jlong j_end_time) {
+ if (!j_uri) {
+ return;
+ }
+ auto uri = JniUtils::ToStrView(j_env, j_uri);
+ auto scope = GetScope(j_scope_id);
+ auto runner = scope->GetEngine().lock()->GetJsTaskRunner();
+ if (runner) {
+ std::weak_ptr weak_scope = scope;
+ auto task = [weak_scope, uri, j_start_time, j_end_time]() {
+ auto scope = weak_scope.lock();
+ if (scope) {
+ auto entry = scope->GetPerformance()->PerformanceResource(uri);
+ entry->SetLoadSourceStart(footstone::TimePoint::FromEpochDelta(footstone::TimeDelta::FromMilliseconds(j_start_time)));
+ entry->SetLoadSourceEnd(footstone::TimePoint::FromEpochDelta(footstone::TimeDelta::FromMilliseconds(j_end_time)));
+ }
+ };
+ runner->PostTask(std::move(task));
+ }
+}
+
jint CreateJsDriver(JNIEnv* j_env,
jobject j_object,
jbyteArray j_global_config,
@@ -153,6 +222,10 @@ jint CreateJsDriver(JNIEnv* j_env,
<< ", j_is_dev_module = "
<< static_cast(j_is_dev_module)
<< ", j_group_id = " << j_group_id;
+
+ // perfromance start time
+ auto perf_start_time = footstone::TimePoint::SystemNow();
+
auto global_config = JniUtils::JByteArrayToStrView(j_env, j_global_config);
auto java_callback = std::make_shared(j_env, j_callback);
@@ -196,10 +269,16 @@ jint CreateJsDriver(JNIEnv* j_env,
auto dom_task_runner = dom_manager_object->GetTaskRunner();
auto bridge = std::make_shared(j_env, j_object);
auto scope_id = hippy::global_data_holder_key.fetch_add(1);
- auto scope_initialized_callback = [
+ auto scope_initialized_callback = [perf_start_time,
scope_id, java_callback, bridge, &holder = hippy::global_data_holder](std::shared_ptr scope) {
scope->SetBridge(bridge);
holder.Insert(scope_id, scope);
+
+ // perfromance end time
+ auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->SetHippyJsEngineInitStart(perf_start_time);
+ entry->SetHippyJsEngineInitEnd(footstone::TimePoint::SystemNow());
+
FOOTSTONE_LOG(INFO) << "run scope cb";
hippy::bridge::CallJavaMethod(java_callback->GetObj(), INIT_CB_STATE::SUCCESS);
};
diff --git a/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java b/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java
index 74abcdecc33..560633b5f86 100644
--- a/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java
+++ b/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java
@@ -69,6 +69,18 @@ public void reportException(String message, String stackTrace) {
}
}
+ public void recordNativeInitEndTime(long startTime, long endTime) {
+ onNativeInitEnd(mInstanceId, startTime, endTime);
+ }
+
+ public void recordFirstFrameEndTime(long time) {
+ onFirstFrameEnd(mInstanceId, time);
+ }
+
+ public void recordResourceLoadEndTime(@NonNull String uri, long startTime, long endTime) {
+ onResourceLoadEnd(mInstanceId, uri, startTime, endTime);
+ }
+
public void onResourceReady(ByteBuffer output, long resId) {
onResourceReady(mInstanceId, output, resId);
}
@@ -148,4 +160,10 @@ private native void callFunction(int instanceId, String action, NativeCallback c
byte[] buffer, int offset, int length);
private native void onResourceReady(int instanceId, ByteBuffer output, long resId);
+
+ private native void onNativeInitEnd(int instanceId, long startTime, long endTime);
+
+ private native void onFirstFrameEnd(int instanceId, long time);
+
+ private native void onResourceLoadEnd(int instanceId, String uri, long startTime, long endTime);
}
diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java b/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java
index 25a1d549476..5065a6eef75 100644
--- a/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java
+++ b/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.openhippy.connector.JsDriver;
import com.tencent.devtools.DevtoolsManager;
import com.tencent.mtt.hippy.HippyEngine.ModuleLoadStatus;
import com.tencent.mtt.hippy.bridge.HippyBridgeManager;
@@ -41,6 +42,9 @@ public interface HippyEngineContext {
@NonNull
VfsManager getVfsManager();
+ @NonNull
+ JsDriver getJsDriver();
+
@NonNull
TimeMonitor getMonitor();
diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java b/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java
index 39df6b0672a..1054d6a194f 100644
--- a/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java
+++ b/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java
@@ -112,6 +112,7 @@ public abstract class HippyEngineManagerImpl extends HippyEngineManager implemen
private final String mRemoteServerUrl;
private ViewGroup mRootView;
final boolean enableV8Serialization;
+ private long mInitStartTime = 0;
private final TimeMonitor mMonitor;
private final HippyThirdPartyAdapter mThirdPartyAdapter;
private final V8InitParams v8InitParams;
@@ -151,6 +152,7 @@ public void initEngine(EngineListener listener) throws IllegalStateException {
throw new IllegalStateException(
"Cannot repeatedly call engine initialization, current state=" + mCurrentState);
}
+ mInitStartTime = System.currentTimeMillis();
mCurrentState = EngineState.INITING;
if (listener != null) {
mEventListeners.add(listener);
@@ -217,6 +219,7 @@ protected void onDestroyEngine() {
@Override
public void onFirstViewAdded() {
+ mEngineContext.getJsDriver().recordFirstFrameEndTime(System.currentTimeMillis());
MonitorGroup monitorGroup = mEngineContext.getMonitor()
.endGroup(MonitorGroupType.LOAD_INSTANCE);
if (monitorGroup != null) {
@@ -549,6 +552,7 @@ void notifyEngineInitialized(final EngineInitStatus statusCode, final Throwable
}
private void onEngineInitialized(EngineInitStatus statusCode, Throwable error) {
+ mEngineContext.getJsDriver().recordNativeInitEndTime(mInitStartTime, System.currentTimeMillis());
MonitorGroup monitorGroup = mEngineContext.getMonitor()
.endGroup(MonitorGroupType.ENGINE_INITIALIZE);
if (monitorGroup != null) {
@@ -727,8 +731,10 @@ public class HippyEngineContextImpl implements HippyEngineContext,
public HippyEngineContextImpl(@Nullable DomManager domManager) throws RuntimeException {
mVfsManager = (mProcessors != null) ? new VfsManager(mProcessors) : new VfsManager();
mVfsManager.setId(onCreateVfs(mVfsManager));
- DefaultProcessor processor = new DefaultProcessor(new HippyResourceLoader(this));
- mVfsManager.addProcessorAtLast(processor);
+ DefaultProcessor defaultProcessor = new DefaultProcessor(new HippyResourceLoader(this));
+ PerformanceProcessor performanceProcessor = new PerformanceProcessor(this);
+ mVfsManager.addProcessorAtFirst(performanceProcessor);
+ mVfsManager.addProcessorAtLast(defaultProcessor);
if (mDebugMode) {
mDevtoolsManager = new DevtoolsManager(true);
String localCachePath = getGlobalConfigs().getContext().getCacheDir()
@@ -792,6 +798,12 @@ public void onRuntimeInitialized() {
}
}
+ @Override
+ @NonNull
+ public JsDriver getJsDriver() {
+ return mJsDriver;
+ }
+
@NonNull
DomManager getDomManager() {
return mDomManager;
diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/PerformanceProcessor.java b/framework/android/src/main/java/com/tencent/mtt/hippy/PerformanceProcessor.java
new file mode 100644
index 00000000000..f2bb7ce0de8
--- /dev/null
+++ b/framework/android/src/main/java/com/tencent/mtt/hippy/PerformanceProcessor.java
@@ -0,0 +1,80 @@
+/* Tencent is pleased to support the open source community by making Hippy available.
+ * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tencent.mtt.hippy;
+
+import androidx.annotation.NonNull;
+import com.tencent.vfs.Processor;
+import com.tencent.vfs.ResourceDataHolder;
+import com.tencent.vfs.ResourceDataHolder.RequestFrom;
+import com.tencent.vfs.UrlUtils;
+import com.tencent.vfs.VfsManager.ProcessorCallback;
+import java.lang.ref.WeakReference;
+
+/**
+ * For performance API features, we need to add this processor at the head of the vfs access chain
+ * for recording the start and end of resource loading.
+ */
+public class PerformanceProcessor extends Processor {
+
+ private final WeakReference mEngineContextRef;
+
+ public PerformanceProcessor(@NonNull HippyEngineContext engineContext) {
+ mEngineContextRef = new WeakReference<>(engineContext);
+ }
+
+ @Override
+ public void handleRequestAsync(@NonNull ResourceDataHolder holder,
+ @NonNull ProcessorCallback callback) {
+ if (holder.requestFrom == RequestFrom.LOCAL) {
+ holder.loadStartTime = System.currentTimeMillis();
+ }
+ super.handleRequestAsync(holder, callback);
+ }
+
+ @Override
+ public boolean handleRequestSync(@NonNull ResourceDataHolder holder) {
+ if (holder.requestFrom == RequestFrom.LOCAL) {
+ holder.loadStartTime = System.currentTimeMillis();
+ }
+ return super.handleRequestSync(holder);
+ }
+
+ @Override
+ public void handleResponseAsync(@NonNull ResourceDataHolder holder,
+ @NonNull ProcessorCallback callback) {
+ HippyEngineContext engineContext = mEngineContextRef.get();
+ if (shouldDoRecord(holder) && engineContext != null) {
+ engineContext.getJsDriver().recordResourceLoadEndTime(holder.uri, holder.loadStartTime,
+ System.currentTimeMillis());
+ }
+ super.handleResponseAsync(holder, callback);
+ }
+
+ @Override
+ public void handleResponseSync(@NonNull ResourceDataHolder holder) {
+ HippyEngineContext engineContext = mEngineContextRef.get();
+ if (shouldDoRecord(holder) && engineContext != null) {
+ engineContext.getJsDriver().recordResourceLoadEndTime(holder.uri, holder.loadStartTime,
+ System.currentTimeMillis());
+ }
+ super.handleResponseSync(holder);
+ }
+
+ private boolean shouldDoRecord(@NonNull ResourceDataHolder holder) {
+ return holder.requestFrom != RequestFrom.NATIVE && !UrlUtils.isBase64Url(holder.uri);
+ }
+}
diff --git a/framework/ios/base/HippyPerformanceLogger.h b/framework/ios/base/HippyPerformanceLogger.h
deleted file mode 100644
index b041f4d8f80..00000000000
--- a/framework/ios/base/HippyPerformanceLogger.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*!
- * iOS SDK
- *
- * Tencent is pleased to support the open source community by making
- * Hippy available.
- *
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.
- * All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import
-
-typedef NS_ENUM(NSUInteger, HippyPLTag) {
- HippyPLScriptDownload = 0, //bundle download tag
- HippyExecuteSource, //bundle execution tag
- HippyPLBundleSize, //bundle size tag
-
- HippyPLNativeModuleInit, //native module initialization tag
- HippyPLJSExecutorSetup, //js executor setup tag
- HippyPLBridgeStartup, //bridge set up tag
- HippyPLSize
-};
-
-@interface HippyPerformanceLogger : NSObject
-
-/**
- * Starts measuring a metric with the given tag.
- * Overrides previous value if the measurement has been already started.
- * If HippyProfile is enabled it also begins appropriate async event.
- * All work is scheduled on the background queue so this doesn't block current thread.
- */
-- (void)markStartForTag:(HippyPLTag)tag forKey:(NSString *)key;
-
-/**
- * Stops measuring a metric with given tag.
- * Checks if HippyPerformanceLoggerStart() has been called before
- * and doesn't do anything and log a message if it hasn't.
- * If HippyProfile is enabled it also ends appropriate async event.
- * All work is scheduled on the background queue so this doesn't block current thread.
- */
-- (void)markStopForTag:(HippyPLTag)tag forKey:(NSString *)key;
-
-/**
- * Sets given value for a metric with given tag.
- * All work is scheduled on the background queue so this doesn't block current thread.
- */
-- (void)setValue:(int64_t)value forTag:(HippyPLTag)tag forKey:(NSString *)key;
-
-/**
- * Adds given value to the current value for a metric with given tag.
- * All work is scheduled on the background queue so this doesn't block current thread.
- */
-- (void)addValue:(int64_t)value forTag:(HippyPLTag)tag forKey:(NSString *)key;
-
-/**
- * Returns a duration in ms (stop_time - start_time) for given HippyPLTag.
- */
-- (int64_t)durationForTag:(HippyPLTag)tag forKey:(NSString *)key;
-
-/**
- * Returns a value for given HippyPLTag.
- */
-- (int64_t)valueForTag:(HippyPLTag)tag forKey:(NSString *)key;
-
-/**
- * Returns an array with values for all tags.
- * Use HippyPLTag to go over the array.
- */
-- (NSArray *)labelsForTags;
-
-@end
diff --git a/framework/ios/base/HippyPerformanceLogger.mm b/framework/ios/base/HippyPerformanceLogger.mm
deleted file mode 100644
index dcc056e59e6..00000000000
--- a/framework/ios/base/HippyPerformanceLogger.mm
+++ /dev/null
@@ -1,119 +0,0 @@
-/*!
- * iOS SDK
- *
- * Tencent is pleased to support the open source community by making
- * Hippy available.
- *
- * Copyright (C) 2019 THL A29 Limited, a Tencent company.
- * All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import
-
-#import "HippyPerformanceLogger.h"
-#import "HPLog.h"
-
-#include
-
-struct PerformanceValue {
- int64_t startTime;
- int64_t endTime;
- PerformanceValue():startTime(0), endTime(0) {}
-};
-
-struct NSStringHash {
- std::size_t operator()(const NSString* str) const {
- return [str hash];
- }
-};
-
-struct NSStringEqual {
- bool operator()(const NSString* lhs, const NSString* rhs) const {
- return 0 == std::strcmp([lhs UTF8String], [rhs UTF8String]);
- }
-};
-
-using PerformanceTagValue = std::unordered_map;
-using PerformanceMap = std::unordered_map;
-@interface HippyPerformanceLogger () {
- PerformanceMap _data;
-}
-
-@property (nonatomic, copy) NSArray *labelsForTags;
-
-@end
-
-@implementation HippyPerformanceLogger
-
-- (instancetype)init {
- if (self = [super init]) {
- _labelsForTags = @[
- @"ScriptDownload",
- @"ScriptExecution",
- @"NativeModuleInit",
- @"JSExecutorSetup",
- @"BridgeStartup",
- @"BundleSize",
- @"ExecuteSource",
- ];
- _data.reserve(HippyPLSize);
- }
- return self;
-}
-
-- (PerformanceValue &)getPLValue:(HippyPLTag)tag forKey:(NSString *)key {
- NSString *finalKey = key ?: [NSString stringWithFormat:@"%p", self];
- PerformanceTagValue &tagValue = _data[tag];
- PerformanceValue &value = tagValue[finalKey];
- return value;
-}
-
-- (void)markStartForTag:(HippyPLTag)tag forKey:(NSString *)key {
- PerformanceValue &value = [self getPLValue:tag forKey:key];
- value.startTime = CACurrentMediaTime() * 1000.f;
-}
-
-- (void)markStopForTag:(HippyPLTag)tag forKey:(NSString *)key {
- PerformanceValue &value = [self getPLValue:tag forKey:key];
- if (value.startTime != 0 && value.endTime == 0) {
- value.endTime = CACurrentMediaTime() * 1000.f;
- }
- else {
- HPLogInfo(@"[Hippy_OC_Log][Performance],Unbalanced calls start/end for tag %li", (unsigned long)tag);
- }
-}
-
-- (void)setValue:(int64_t)value forTag:(HippyPLTag)tag forKey:(NSString *)key {
- PerformanceValue &pvalue = [self getPLValue:tag forKey:key];
- pvalue.startTime = 0;
- pvalue.endTime = value;
-}
-
-- (void)addValue:(int64_t)value forTag:(HippyPLTag)tag forKey:(NSString *)key {
- PerformanceValue &pvalue = [self getPLValue:tag forKey:key];
- pvalue.startTime = pvalue.startTime + value;
-}
-
-- (int64_t)durationForTag:(HippyPLTag)tag forKey:(NSString *)key {
- PerformanceValue &value = [self getPLValue:tag forKey:key];
- return value.endTime - value.startTime;
-}
-
-- (int64_t)valueForTag:(HippyPLTag)tag forKey:(NSString *)key {
- PerformanceValue &value = [self getPLValue:tag forKey:key];
- return value.endTime;
-}
-
-@end
diff --git a/framework/ios/base/bridge/HippyBridge.h b/framework/ios/base/bridge/HippyBridge.h
index 578706d431e..c9024cf72b9 100644
--- a/framework/ios/base/bridge/HippyBridge.h
+++ b/framework/ios/base/bridge/HippyBridge.h
@@ -32,7 +32,6 @@
#include
-@class HippyPerformanceLogger;
@class HippyJSExecutor;
@class HippyModuleData;
@@ -42,6 +41,7 @@ namespace hippy {
inline namespace dom {
class DomManager;
class RootNode;
+class RenderManager;
};
};
@@ -90,6 +90,8 @@ HP_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass);
@property (nonatomic, copy, readonly) NSDictionary *launchOptions;
+@property (nonatomic, assign) std::weak_ptr renderManager;
+
/**
* Create A HippyBridge instance
*
@@ -251,11 +253,6 @@ HP_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass);
*/
- (void)requestReload;
-/**
- * Link to the Performance Logger that logs Hippy Native perf events.
- */
-@property (nonatomic, readonly, strong) HippyPerformanceLogger *performanceLogger;
-
@property (nonatomic, assign) BOOL debugMode;
@property (nonatomic, strong) NSString *appVerson; //
diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm
index d14e7b249cf..7c31e7a8355 100644
--- a/framework/ios/base/bridge/HippyBridge.mm
+++ b/framework/ios/base/bridge/HippyBridge.mm
@@ -36,11 +36,9 @@
#import "HippyModuleMethod.h"
#import "HippyTurboModuleManager.h"
#import "HippyOCTurboModule.h"
-#import "HippyPerformanceLogger.h"
#import "HippyRedBox.h"
#import "HippyTurboModule.h"
#import "HippyUtils.h"
-
#import "HPAsserts.h"
#import "HPConvert.h"
#import "HPDefaultImageProvider.h"
@@ -49,6 +47,7 @@
#import "HPLog.h"
#import "HPOCToHippyValue.h"
#import "HPToolUtils.h"
+#import "NSObject+Render.h"
#import "TypeConverter.h"
#import "VFSUriLoader.h"
@@ -61,6 +60,7 @@
#include "dom/scene.h"
#include "dom/render_manager.h"
#include "driver/scope.h"
+#include "driver/performance/performance.h"
#include "footstone/worker_manager.h"
#include "vfs/uri_loader.h"
#include "VFSUriHandler.h"
@@ -97,6 +97,8 @@ @interface HippyBridge() {
NSMutableArray *_bundleURLs;
NSURL *_sandboxDirectory;
std::weak_ptr _uriLoader;
+ std::weak_ptr _renderManager;
+ footstone::TimePoint _startTime;
}
@property(readwrite, strong) dispatch_semaphore_t moduleSemaphore;
@@ -142,6 +144,8 @@ - (instancetype)initWithDelegate:(id)delegate
_invalidateReason = HPInvalidateReasonDealloc;
_valid = YES;
_bundlesQueue = [[HippyBundleOperationQueue alloc] init];
+ _startTime = footstone::TimePoint::SystemNow();
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rootViewContentDidAppear:) name:kRootViewDidAddContent object:nil];
[self setUp];
HPExecuteOnMainThread(^{
[self bindKeys];
@@ -151,6 +155,20 @@ - (instancetype)initWithDelegate:(id)delegate
return self;
}
+- (void)rootViewContentDidAppear:(NSNotification *)noti {
+ UIView *rootView = [[noti userInfo] objectForKey:kRootViewKey];
+ if (rootView) {
+ auto domManager = _javaScriptExecutor.pScope->GetDomManager().lock();
+ if (domManager) {
+ auto viewRenderManager = [rootView renderManager];
+ if (_renderManager.lock() == viewRenderManager.lock()) {
+ auto entry = _javaScriptExecutor.pScope->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->SetHippyFirstFrameEnd(footstone::TimePoint::SystemNow());
+ }
+ }
+ }
+}
+
- (void)dealloc {
/**
* This runs only on the main thread, but crashes the subclass
@@ -240,14 +258,11 @@ - (void)requestReload {
}
- (void)setUp {
- _performanceLogger = [HippyPerformanceLogger new];
- [_performanceLogger markStartForTag:HippyPLBridgeStartup forKey:nil];
_valid = YES;
self.moduleSemaphore = dispatch_semaphore_create(0);
@try {
__weak HippyBridge *weakSelf = self;
_moduleSetup = [[HippyModulesSetup alloc] initWithBridge:self extraProviderModulesBlock:_moduleProvider];
- [_performanceLogger markStartForTag:HippyPLJSExecutorSetup forKey:nil];
_javaScriptExecutor = [[HippyJSExecutor alloc] initWithEngineKey:_engineKey bridge:self];
_javaScriptExecutor.contextCreatedBlock = ^(id ctxWrapper){
HippyBridge *strongSelf = weakSelf;
@@ -255,7 +270,6 @@ - (void)setUp {
dispatch_semaphore_wait(strongSelf.moduleSemaphore, DISPATCH_TIME_FOREVER);
NSString *moduleConfig = [strongSelf moduleConfig];
[ctxWrapper createGlobalObject:@"__hpBatchedBridgeConfig" withJsonValue:moduleConfig];
- [strongSelf->_performanceLogger markStopForTag:HippyPLJSExecutorSetup forKey:nil];
#if HP_DEV
//default is yes when debug mode
[strongSelf setInspectable:YES];
@@ -270,17 +284,21 @@ - (void)setUp {
//The caller may attempt to look up a module immediately after creating the HippyBridge,
//therefore the initialization of all modules cannot be placed in a sub-thread
// dispatch_async(HippyBridgeQueue(), ^{
- [self initWithModulesCompletion:^{
- HippyBridge *strongSelf = weakSelf;
- if (strongSelf) {
- dispatch_semaphore_signal(strongSelf.moduleSemaphore);
- }
- }];
+ [self initWithModulesCompletion:^{
+ HippyBridge *strongSelf = weakSelf;
+ if (strongSelf) {
+ dispatch_semaphore_signal(strongSelf.moduleSemaphore);
+ footstone::TimePoint endTime = footstone::TimePoint::SystemNow();
+ auto enty =
+ strongSelf.javaScriptExecutor.pScope->GetPerformance()->PerformanceNavigation("hippyInit");
+ enty->SetHippyNativeInitStart(strongSelf->_startTime);
+ enty->SetHippyNativeInitEnd(endTime);
+ }
+ }];
// });
} @catch (NSException *exception) {
HippyBridgeHandleException(exception, self);
}
- [_performanceLogger markStopForTag:HippyPLBridgeStartup forKey:nil];
}
- (void)loadBundleURL:(NSURL *)bundleURL
@@ -302,9 +320,7 @@ - (void)loadBundleURL:(NSURL *)bundleURL
- (void)initWithModulesCompletion:(dispatch_block_t)completion {
- [_performanceLogger markStartForTag:HippyPLNativeModuleInit forKey:nil];
[_moduleSetup setupModulesCompletion:completion];
- [_performanceLogger markStopForTag:HippyPLNativeModuleInit forKey:nil];
}
- (void)beginLoadingBundle:(NSURL *)bundleURL
@@ -437,13 +453,11 @@ - (void)executeJSCode:(NSData *)script
return;
}
HPAssert(self.javaScriptExecutor, @"js executor must not be null");
- [_performanceLogger markStartForTag:HippyExecuteSource forKey:[sourceURL absoluteString]];
__weak HippyBridge *weakSelf = self;
[self.javaScriptExecutor executeApplicationScript:script sourceURL:sourceURL onComplete:^(id result ,NSError *error) {
HippyBridge *strongSelf = weakSelf;
if (!strongSelf || ![strongSelf isValid]) {
completion(result, error);
- [strongSelf->_performanceLogger markStopForTag:HippyExecuteSource forKey:[sourceURL absoluteString]];
return;
}
if (error) {
@@ -457,7 +471,6 @@ - (void)executeJSCode:(NSData *)script
userInfo:userInfo];
});
}
- [strongSelf->_performanceLogger markStopForTag:HippyExecuteSource forKey:[sourceURL absoluteString]];
completion(result, error);
}];
}
@@ -820,6 +833,7 @@ - (void)invalidate {
_displayLink = nil;
_javaScriptExecutor = nil;
_moduleSetup = nil;
+ _startTime = footstone::TimePoint::SystemNow();
self.moduleSemaphore = nil;
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[jsExecutor executeBlockOnJavaScriptQueue:^{
diff --git a/framework/ios/base/bridge/HippyConvenientBridge.mm b/framework/ios/base/bridge/HippyConvenientBridge.mm
index 8d2d68a67f2..2d4dbfa8f2f 100644
--- a/framework/ios/base/bridge/HippyConvenientBridge.mm
+++ b/framework/ios/base/bridge/HippyConvenientBridge.mm
@@ -77,12 +77,14 @@ - (void)setUpNativeRenderManager {
auto domManager = engineResource->GetDomManager();
//Create NativeRenderManager
_nativeRenderManager = std::make_shared();
+ _nativeRenderManager->Initialize();
//set dom manager
_nativeRenderManager->SetDomManager(domManager);
//set image provider for native render manager
_nativeRenderManager->AddImageProviderClass([HPDefaultImageProvider class]);
_nativeRenderManager->RegisterExtraComponent(_extraComponents);
_nativeRenderManager->SetVFSUriLoader([self URILoader]);
+ _bridge.renderManager = _nativeRenderManager;
}
- (std::shared_ptr)URILoader {
@@ -155,7 +157,9 @@ - (void)setRootView:(UIView *)rootView {
_rootNode->SetRootSize(rootView.frame.size.width, rootView.frame.size.height);
//set rendermanager for dommanager
- domManager->SetRenderManager(_nativeRenderManager);
+ if (!domManager->GetRenderManager().lock()) {
+ domManager->SetRenderManager(_nativeRenderManager);
+ }
//bind rootview and root node
_nativeRenderManager->RegisterRootView(rootView, _rootNode);
diff --git a/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm b/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm
index 636aaba6f14..7a8f876b9ea 100644
--- a/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm
+++ b/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm
@@ -22,7 +22,6 @@
#import "HippyBundleLoadOperation.h"
#import "HippyBridge+VFSLoader.h"
-#import "HippyPerformanceLogger.h"
#include
@@ -71,8 +70,6 @@ - (void)main {
self.executing = YES;
HippyBridge *bridge = _bridge;
NSString *bundleURL = [_bundleURL absoluteString];
- HippyPerformanceLogger *performanceLogger = bridge?bridge.performanceLogger:nil;
- [performanceLogger markStartForTag:HippyPLScriptDownload forKey:bundleURL];
__weak HippyBundleLoadOperation *weakSelf = self;
[bridge loadContentsAsynchronouslyFromUrl:bundleURL
method:@"get"
@@ -87,9 +84,6 @@ - (void)main {
strongSelf.executing = NO;
return;
}
- int64_t sourceLength = [data length];
- [performanceLogger markStopForTag:HippyPLScriptDownload forKey:bundleURL];
- [performanceLogger setValue:sourceLength forTag:HippyPLBundleSize forKey:bundleURL];
if (strongSelf.onLoad) {
strongSelf.onLoad(data, error);
}
diff --git a/framework/ios/base/executors/HippyJSExecutor.mm b/framework/ios/base/executors/HippyJSExecutor.mm
index beb4e42e096..e2c77f31b3a 100644
--- a/framework/ios/base/executors/HippyJSExecutor.mm
+++ b/framework/ios/base/executors/HippyJSExecutor.mm
@@ -31,7 +31,6 @@
#import "HippyJSEnginesMapper.h"
#import "HippyJSExecutor.h"
#import "HippyOCTurboModule+Inner.h"
-#import "HippyPerformanceLogger.h"
#import "HippyRedBox.h"
#import "HippyUtils.h"
#import "HippyTurboModuleManager.h"
@@ -78,7 +77,6 @@
@interface HippyJSExecutor () {
// Set at setUp time:
- HippyPerformanceLogger *_performanceLogger;
id _contextWrapper;
NSMutableArray *_pendingCalls;
__weak HippyBridge *_bridge;
@@ -95,7 +93,6 @@ @implementation HippyJSExecutor
- (void)setBridge:(HippyBridge *)bridge {
_bridge = bridge;
- _performanceLogger = [bridge performanceLogger];
}
- (HippyBridge *)bridge {
@@ -105,9 +102,11 @@ - (HippyBridge *)bridge {
- (void)setup {
auto engine = [[HippyJSEnginesMapper defaultInstance] createJSEngineResourceForKey:self.enginekey];
const char *pName = [self.enginekey UTF8String] ?: "";
+ footstone::TimePoint startPoint = footstone::TimePoint::SystemNow();
auto scope = engine->GetEngine()->CreateScope(pName);
+ dispatch_semaphore_t scopeSemaphore = dispatch_semaphore_create(0);
__weak HippyJSExecutor *weakSelf = self;
- engine->GetEngine()->GetJsTaskRunner()->PostTask([weakSelf](){
+ engine->GetEngine()->GetJsTaskRunner()->PostTask([weakSelf, scopeSemaphore, startPoint](){
@autoreleasepool {
HippyJSExecutor *strongSelf = weakSelf;
if (!strongSelf) {
@@ -117,6 +116,7 @@ - (void)setup {
if (!bridge) {
return;
}
+ dispatch_semaphore_wait(scopeSemaphore, DISPATCH_TIME_FOREVER);
auto scope = strongSelf->_pScope;
scope->CreateContext();
auto context = scope->GetContext();
@@ -214,9 +214,13 @@ - (void)setup {
[strongSelf executeBlockOnJavaScriptQueue:obj];
}];
[strongSelf->_pendingCalls removeAllObjects];
+ auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit");
+ entry->SetHippyJsEngineInitStart(startPoint);
+ entry->SetHippyJsEngineInitEnd(footstone::TimePoint::SystemNow());
}
});
self.pScope = scope;
+ dispatch_semaphore_signal(scopeSemaphore);
#ifdef ENABLE_INSPECTOR
HippyBridge *bridge = self.bridge;
if (bridge && bridge.debugMode) {
@@ -522,10 +526,8 @@ - (void)_executeJSCall:(NSString *)method
- (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)sourceURL onComplete:(HippyJavaScriptCallback)onComplete {
HPAssertParam(script);
HPAssertParam(sourceURL);
- // HippyProfileBeginFlowEvent();
__weak HippyJSExecutor* weakSelf = self;
[self executeBlockOnJavaScriptQueue:^{
- // HippyProfileEndFlowEvent();
@autoreleasepool {
HippyJSExecutor *strongSelf = weakSelf;
if (!strongSelf || !strongSelf.isValid) {
@@ -533,7 +535,7 @@ - (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)sourceURL o
return;
}
NSError *error = nil;
- id result = executeApplicationScript(script, sourceURL, strongSelf->_performanceLogger, strongSelf.pScope->GetContext(), &error);
+ id result = executeApplicationScript(script, sourceURL, strongSelf.pScope->GetContext(), &error);
if (onComplete) {
onComplete(result, error);
}
@@ -550,7 +552,7 @@ - (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)sourceURL o
return lock;
}
-static NSError *executeApplicationScript(NSData *script, NSURL *sourceURL, HippyPerformanceLogger *performanceLogger, SharedCtxPtr context, NSError **error) {
+static NSError *executeApplicationScript(NSData *script, NSURL *sourceURL, SharedCtxPtr context, NSError **error) {
@autoreleasepool {
const char *scriptBytes = reinterpret_cast([script bytes]);
string_view view = string_view::new_from_utf8(scriptBytes, [script length]);
diff --git a/framework/voltron/core/src/bridge/ios/VoltronJSCExecutor.mm b/framework/voltron/core/src/bridge/ios/VoltronJSCExecutor.mm
index 8109813d0a8..905d6fd8c93 100644
--- a/framework/voltron/core/src/bridge/ios/VoltronJSCExecutor.mm
+++ b/framework/voltron/core/src/bridge/ios/VoltronJSCExecutor.mm
@@ -199,11 +199,11 @@ - (void)setup {
std::shared_ptr context = std::static_pointer_cast(scope->GetContext());
JSContext *jsContext = [JSContext contextWithJSGlobalContextRef:context->GetCtxRef()];
-// #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_16_2
-// if (@available(iOS 16.4, *)) {
-// jsContext.inspectable = true;
-// }
-// #endif
+ #if defined(__IPHONE_16_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_4
+ if (@available(iOS 16.4, *)) {
+ jsContext.inspectable = true;
+ }
+ #endif
auto global_object = context->GetGlobalObject();
auto user_global_object_key = context->CreateString(kGlobalKey);
context->SetProperty(global_object, user_global_object_key, global_object);
diff --git a/hippy.podspec b/hippy.podspec
index e84385191e8..0058da1d5b0 100644
--- a/hippy.podspec
+++ b/hippy.podspec
@@ -69,6 +69,10 @@ Pod::Spec.new do |s|
'GCC_ENABLE_CPP_EXCEPTIONS' => false,
'GCC_ENABLE_CPP_RTTI' => false,
}
+ framework.dependency 'hippy/Base'
+ framework.dependency 'hippy/JSDriver'
+ framework.dependency 'hippy/Image'
+ framework.dependency 'hippy/NativeRenderer'
puts 'hippy subspec \'framework\' read end'
end
@@ -110,6 +114,7 @@ Pod::Spec.new do |s|
'GCC_ENABLE_CPP_RTTI' => false,
}
footstoneutils.dependency 'hippy/Footstone'
+ footstoneutils.dependency 'hippy/Base'
puts 'hippy subspec \'footstoneutils\' read end'
end
@@ -127,6 +132,7 @@ Pod::Spec.new do |s|
base.libraries = 'c++'
base.source_files = ['modules/ios/base/*.{h,m,mm}', 'modules/ios/logutils/*.{h,mm}']
base.public_header_files = ['modules/ios/base/*.h', 'modules/ios/logutils/*.h']
+ base.dependency 'hippy/Footstone'
puts 'hippy subspec \'base\' read end'
end
@@ -151,6 +157,7 @@ Pod::Spec.new do |s|
'HEADER_SEARCH_PATHS' => header_search_paths
}
vfs.preserve_path = 'modules/vfs/native'
+ vfs.dependency 'hippy/Footstone'
puts 'hippy subspec \'vfs\' read end'
end
@@ -165,6 +172,8 @@ Pod::Spec.new do |s|
'GCC_ENABLE_CPP_RTTI' => false,
}
iosvfs.dependency 'hippy/VFS'
+ iosvfs.dependency 'hippy/Footstone'
+ iosvfs.dependency 'hippy/FootstoneUtils'
puts 'hippy subspec \'iosvfs\' read end'
end
@@ -225,6 +234,9 @@ Pod::Spec.new do |s|
driver.user_target_xcconfig = {
'HEADER_SEARCH_PATHS' => header_search_paths,
}
+ driver.dependency 'hippy/Footstone'
+ driver.dependency 'hippy/Dom'
+ driver.dependency 'hippy/iOSVFS'
driver.preserve_path = 'driver/js'
puts 'hippy subspec \'driver\' read end'
end
@@ -234,6 +246,10 @@ Pod::Spec.new do |s|
renderer.libraries = 'c++'
renderer.source_files = 'renderer/native/ios/**/*.{h,m,mm}'
renderer.public_header_files = 'renderer/native/ios/**/*.h'
+ renderer.dependency 'hippy/Base'
+ renderer.dependency 'hippy/DomUtils'
+ renderer.dependency 'hippy/Image'
+ renderer.dependency 'hippy/iOSVFS'
puts 'hippy subspec \'nativerenderer\' read end'
end
@@ -291,6 +307,8 @@ Pod::Spec.new do |s|
'GCC_ENABLE_CPP_RTTI' => false,
}
domutils.dependency 'hippy/Dom'
+ domutils.dependency 'hippy/FootstoneUtils'
+ domutils.dependency 'hippy/Base'
puts 'hippy subspec \'domutils\' read end'
end
diff --git a/modules/footstone/include/footstone/time_point.h b/modules/footstone/include/footstone/time_point.h
index a25fa484354..9f038bc7fab 100644
--- a/modules/footstone/include/footstone/time_point.h
+++ b/modules/footstone/include/footstone/time_point.h
@@ -42,6 +42,12 @@ class TimePoint {
.count());
}
+ static TimePoint SystemNow() {
+ return TimePoint(std::chrono::duration_cast(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count());
+ }
+
static constexpr TimePoint Min() { return TimePoint(std::numeric_limits::min()); }
static constexpr TimePoint Max() { return TimePoint(std::numeric_limits::max()); }
diff --git a/modules/ios/base/MacroDefines.h b/modules/ios/base/MacroDefines.h
index 423181d3dda..6be51b67366 100644
--- a/modules/ios/base/MacroDefines.h
+++ b/modules/ios/base/MacroDefines.h
@@ -67,3 +67,6 @@
*/
#define HP_CONCAT2(A, B) A##B
#define HP_CONCAT(A, B) HP_CONCAT2(A, B)
+
+#define kRootViewDidAddContent @"RootViewDidAddContent"
+#define kRootViewKey @"RootViewKey"
diff --git a/modules/ios/base/NSObject+Render.h b/modules/ios/base/NSObject+Render.h
new file mode 100644
index 00000000000..de33d40859e
--- /dev/null
+++ b/modules/ios/base/NSObject+Render.h
@@ -0,0 +1,41 @@
+/*!
+ * iOS SDK
+ *
+ * Tencent is pleased to support the open source community by making
+ * Hippy available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import
+
+#include
+
+NS_ASSUME_NONNULL_BEGIN
+
+namespace hippy {
+inline namespace dom {
+class RenderManager;
+};
+};
+
+@interface NSObject (Render)
+
+@property(nonatomic, assign) std::weak_ptr renderManager;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/modules/ios/base/NSObject+Render.mm b/modules/ios/base/NSObject+Render.mm
new file mode 100644
index 00000000000..d6f5fa6dd49
--- /dev/null
+++ b/modules/ios/base/NSObject+Render.mm
@@ -0,0 +1,51 @@
+/*!
+ * iOS SDK
+ *
+ * Tencent is pleased to support the open source community by making
+ * Hippy available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "NSObject+Render.h"
+#import "objc/runtime.h"
+
+#include "dom/render_manager.h"
+
+@interface RenderManagerWrapper : NSObject
+
+@property(nonatomic, assign) std::weak_ptr renderManager;
+
+@end
+
+@implementation RenderManagerWrapper
+
+@end
+
+@implementation NSObject (Render)
+
+- (void)setRenderManager:(std::weak_ptr)renderManager {
+ RenderManagerWrapper *wrapper = [[RenderManagerWrapper alloc] init];
+ wrapper.renderManager = renderManager;
+ objc_setAssociatedObject(self, @selector(renderManager), wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (std::weak_ptr)renderManager {
+ RenderManagerWrapper *wrapper = objc_getAssociatedObject(self, _cmd);
+ return wrapper.renderManager;
+}
+
+@end
diff --git a/modules/vfs/android/src/main/java/com/tencent/vfs/ResourceDataHolder.java b/modules/vfs/android/src/main/java/com/tencent/vfs/ResourceDataHolder.java
index 6a1b6c958c5..57cdb91c0b7 100644
--- a/modules/vfs/android/src/main/java/com/tencent/vfs/ResourceDataHolder.java
+++ b/modules/vfs/android/src/main/java/com/tencent/vfs/ResourceDataHolder.java
@@ -59,6 +59,7 @@ public enum TransferType {
public RequestFrom requestFrom;
public int nativeRequestId;
public int index = -1;
+ public long loadStartTime = 0;
// The resource loading error code is defined by the processor itself,
// a value other than 0 indicates failure, and a value of 0 indicates success.
public int resultCode = -1;
@@ -106,6 +107,7 @@ public void recycle() {
callback = null;
errorMessage = null;
processorTag = null;
+ loadStartTime = 0;
index = -1;
resultCode = -1;
transferType = TransferType.NORMAL;
diff --git a/modules/vfs/ios/VFSUriLoader.mm b/modules/vfs/ios/VFSUriLoader.mm
index cb9d8a7dcbe..438be059332 100644
--- a/modules/vfs/ios/VFSUriLoader.mm
+++ b/modules/vfs/ios/VFSUriLoader.mm
@@ -141,7 +141,16 @@
auto &cur_convenient = (*cur_convenient_it);
//check if convenient loader exists, or forward to cpp loader
if (cur_convenient) {
- cur_convenient->RequestUntrustedContent(request, operationQueue, progress, completion, block);
+ auto startPoint = footstone::TimePoint::SystemNow();
+ VFSHandlerCompletionBlock callback = ^(NSData *data, NSURLResponse *response, NSError *error) {
+ auto endPoint = footstone::TimePoint::SystemNow();
+ string_view uri(NSStringToU16StringView([[response URL] absoluteString]));
+ DoRequestTimePerformanceCallback(uri, startPoint, endPoint);
+ if (completion) {
+ completion(data, response, error);
+ }
+ };
+ cur_convenient->RequestUntrustedContent(request, operationQueue, progress, callback, block);
}
else {
string_view uri = NSStringToU8StringView([requestURL absoluteString]);
diff --git a/modules/vfs/native/include/vfs/uri_loader.h b/modules/vfs/native/include/vfs/uri_loader.h
index 93d539bd85e..4d784b5ad5d 100644
--- a/modules/vfs/native/include/vfs/uri_loader.h
+++ b/modules/vfs/native/include/vfs/uri_loader.h
@@ -38,9 +38,11 @@ inline namespace vfs {
class UriLoader: public std::enable_shared_from_this {
public:
using string_view = footstone::string_view;
+ using TimePoint = footstone::TimePoint;
using WorkerManager = footstone::WorkerManager;
using bytes = vfs::UriHandler::bytes;
using RetCode = vfs::JobResponse::RetCode;
+ using RequestTimePerformanceCallback = std::function;
UriLoader();
virtual ~UriLoader() = default;
@@ -73,6 +75,11 @@ class UriLoader: public std::enable_shared_from_this {
void Terminate();
+ void SetRequestTimePerformanceCallback(const RequestTimePerformanceCallback& cb) { on_request_time_performance_ = cb; }
+
+ protected:
+ void DoRequestTimePerformanceCallback(const string_view& uri, const TimePoint& start, const TimePoint& end);
+
private:
std::shared_ptr GetNextHandler(std::list