| @@ -1,5 +1,12 @@ | |||
| 1 | -harmony/doc-viewer/BuildProfile.ets | 1 | +node_modules |
| 2 | -harmony/doc-viewer/oh-package-lock.json5 | 2 | +.vscode |
| 3 | -lib/ | 3 | +/**/.vscode |
| 4 | -node_modules/ | 4 | +bundle.harmony.js |
| 5 | -package-lock.json | 5 | +*.code-workspace |
| 6 | +**/.DS_Store | ||
| 7 | +**/oh-package-lock.json5 | ||
| 8 | +**/BuildProfile.ets | ||
| 9 | +/OHOS_OpenSDK1.0.0/* | ||
| 10 | +lib/* | ||
| 11 | +oh_modules/* | ||
| 12 | +**/oh_modules/* | ||
| @@ -1,3 +1,13 @@ | |||
| 1 | +# v2.8.1-beta.1 | ||
| 2 | + | ||
| 3 | +## Changes | ||
| 4 | + | ||
| 5 | +* Fix: await removeFile before downloadFile to avoid download race condition [#33](https://gitcode.com/CPF-RN/rntpc_react-native-doc-viewer/pull/33) | ||
| 6 | +* Fix: handle invalid fileName in getFilePath and normalize URL scheme [#33](https://gitcode.com/CPF-RN/rntpc_react-native-doc-viewer/pull/33) | ||
| 7 | +* Refactor: reduce download() nesting depth, add missing semicolons and fix codecheck issues [#33](https://gitcode.com/CPF-RN/rntpc_react-native-doc-viewer/pull/33) | ||
| 8 | +* Fix: capture error code in downloadTask fail callback and pass it to JS side [#33](https://gitcode.com/CPF-RN/rntpc_react-native-doc-viewer/pull/33) | ||
| 9 | +* Chore: add OAT.xml open source review configuration [#33](https://gitcode.com/CPF-RN/rntpc_react-native-doc-viewer/pull/33) | ||
| 10 | + | ||
| 1 | # v2.7.9-rc.1 | 11 | # v2.7.9-rc.1 |
| 2 | 12 | ||
| 3 | ## 更新内容 | 13 | ## 更新内容 |
| @@ -0,0 +1,83 @@ | |||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<configuration> | ||
| 3 | + <oatconfig> | ||
| 4 | + <licensefile>LICENSE</licensefile> | ||
| 5 | + <policylist> | ||
| 6 | + <policy name="projectPolicy" desc=""> | ||
| 7 | + <policyitem type="license" name="MIT" path=".*" desc="license under the MIT"/> | ||
| 8 | + </policy> | ||
| 9 | + <policy name="projectPolicy" desc=""> | ||
| 10 | + <policyitem type="compatibility" name="GPL-2.0+" path=".*" desc="Process that runs independently, invoked by the X process."/> | ||
| 11 | + <policyitem type="compatibility" name="Apache-2.0" path=".*" desc="不影响兼容性"/> | ||
| 12 | + <policyitem type="compatibility" name="BSDStyleLicense" path=".*" desc="不影响兼容性" /> | ||
| 13 | + <policyitem type="compatibility" name="MIT" path=".*" desc="不影响兼容性" /> | ||
| 14 | + <policyitem type="compatibility" name="GPLStyleLicense" path=".*" desc="不影响兼容性" /> | ||
| 15 | + </policy> | ||
| 16 | + </policylist> | ||
| 17 | + <filefilterlist> | ||
| 18 | + <filefilter name="copyrightPolicyFilter" desc="Filters for compatibility,license header policies"> | ||
| 19 | + <filteritem type="filepath" name="harmony/doc-viewer/hvigorfile.ts" desc="hvigor构建脚本,DevEco Studio自动生成,不手动修改"/> | ||
| 20 | + <filteritem type="filepath" name="harmony/doc-viewer/src/main/cpp/generated/.*" desc="Codegen生成文件,不手动修改"/> | ||
| 21 | + <filteritem type="filepath" name="harmony/doc-viewer/src/main/ets/generated/.*" desc="Codegen生成文件,不手动修改"/> | ||
| 22 | + <filteritem type="filename" name="*.json5" desc="hvigor配置文件,DevEco Studio自动生成,不手动修改"/> | ||
| 23 | + <filteritem type="filename" name="*/*.json5" desc="hvigor配置文件,DevEco Studio自动生成,不手动修改"/> | ||
| 24 | + <filteritem type="filename" name="*.config.js" desc="工程配置文件,不手动修改"/> | ||
| 25 | + <filteritem type="filename" name=".prettierrc.js" desc="工程配置文件,不手动修改"/> | ||
| 26 | + <filteritem type="filename" name=".yarnrc" desc="工程配置文件,不手动修改"/> | ||
| 27 | + <filteritem type="filename" name=".npmignore" desc="工程配置文件,不手动修改"/> | ||
| 28 | + <filteritem type="filename" name=".ohpmignore" desc="工程配置文件,不手动修改"/> | ||
| 29 | + <filteritem type="filename" name="BuildProfile.ets" desc="工程配置文件,不手动修改"/> | ||
| 30 | + <filteritem type="filename" name="LICENSE" desc="版权文件,不添加版权头"/> | ||
| 31 | + <filteritem type="filename" name="LICENSE.md" desc="版权文件,不添加许可证头"/> | ||
| 32 | + <filteritem type="filename" name="yarn.lock" desc="依赖配置文件,不添加许可证头"/> | ||
| 33 | + <filteritem type="filepath" name="hvigorw" desc="工程模板,不修改版权头,以防有修改版权风险"/> | ||
| 34 | + <filteritem type="filepath" name="hvigorw.bat" desc="工程模板,不修改版权头,以防有修改版权风险"/> | ||
| 35 | + <filteritem type="filepath" name="js/*.js" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 36 | + <filteritem type="filepath" name="js/*.ts" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 37 | + <filteritem type="filepath" name="src/*.js" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 38 | + <filteritem type="filepath" name="src/*.ts" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 39 | + <filteritem type="filepath" name="*.js" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 40 | + <filteritem type="filepath" name="*.ts" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 41 | + <filteritem type="filepath" name="index.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 42 | + <filteritem type="filepath" name="hvigor/hvigor-wrapper.js" desc="工程模板,不修改版权头,以防有修改版权风险"/> | ||
| 43 | + <filteritem type="filepath" name="hvigor/hvigor-config.json5" desc="工程模板,不修改版权头,以防有修改版权风险"/> | ||
| 44 | + <filteritem type="filename" name="buildEnv.sh" desc="构建环境脚本文件,不修改版权头,以防有修改版权风险"/> | ||
| 45 | + <filteritem type="filepath" name="example/**/*" desc="示例工程,不添加版权头"/> | ||
| 46 | + </filefilter> | ||
| 47 | + <filefilter name="defaultPolicyFilter" desc="Filters for compatibility,license header policies"> | ||
| 48 | + <filteritem type="filepath" name="harmony/doc-viewer/hvigorfile.ts" desc="hvigor构建脚本,DevEco Studio自动生成,不手动修改"/> | ||
| 49 | + <filteritem type="filepath" name="harmony/doc-viewer/src/main/cpp/generated/.*" desc="Codegen生成文件,不手动修改"/> | ||
| 50 | + <filteritem type="filepath" name="harmony/doc-viewer/src/main/ets/generated/.*" desc="Codegen生成文件,不手动修改"/> | ||
| 51 | + <filteritem type="filename" name="*.json5" desc="hvigor配置文件,DevEco Studio自动生成,不手动修改"/> | ||
| 52 | + <filteritem type="filename" name="*/*.json5" desc="hvigor配置文件,DevEco Studio自动生成,不手动修改"/> | ||
| 53 | + <filteritem type="filename" name="*.config.js" desc="工程配置文件,不手动修改"/> | ||
| 54 | + <filteritem type="filename" name=".prettierrc.js" desc="工程配置文件,不手动修改"/> | ||
| 55 | + <filteritem type="filename" name=".yarnrc" desc="工程配置文件,不手动修改"/> | ||
| 56 | + <filteritem type="filename" name=".npmignore" desc="工程配置文件,不手动修改"/> | ||
| 57 | + <filteritem type="filename" name=".ohpmignore" desc="工程配置文件,不手动修改"/> | ||
| 58 | + <filteritem type="filename" name="BuildProfile.ets" desc="工程配置文件,不手动修改"/> | ||
| 59 | + <filteritem type="filename" name="LICENSE" desc="版权文件,不添加许可证头"/> | ||
| 60 | + <filteritem type="filename" name="LICENSE.md" desc="版权文件,不添加许可证头"/> | ||
| 61 | + <filteritem type="filename" name="yarn.lock" desc="依赖配置文件,不添加许可证头"/> | ||
| 62 | + <filteritem type="filepath" name="hvigorw" desc="工程模板,不添加许可证头"/> | ||
| 63 | + <filteritem type="filepath" name="hvigorw.bat" desc="工程模板,不添加许可证头"/> | ||
| 64 | + <filteritem type="filepath" name="js/*.js" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 65 | + <filteritem type="filepath" name="js/*.ts" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 66 | + <filteritem type="filepath" name="src/*.js" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 67 | + <filteritem type="filepath" name="src/*.ts" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 68 | + <filteritem type="filepath" name="*.js" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 69 | + <filteritem type="filepath" name="*.ts" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 70 | + <filteritem type="filepath" name="index.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> | ||
| 71 | + <filteritem type="filepath" name="hvigor/hvigor-wrapper.js" desc="工程模板,不修改版权头,以防有修改版权风险"/> | ||
| 72 | + <filteritem type="filepath" name="hvigor/hvigor-config.json5" desc="工程模板,不修改版权头,以防有修改版权风险"/> | ||
| 73 | + <filteritem type="filename" name="buildEnv.sh" desc="构建环境脚本文件,不修改版权头,以防有修改版权风险"/> | ||
| 74 | + <filteritem type="filepath" name="example/**/*" desc="示例工程,不添加版权头"/> | ||
| 75 | + </filefilter> | ||
| 76 | + | ||
| 77 | + <filefilter name="binaryFileTypePolicyFilter" desc="Filters for copyright header policies"> | ||
| 78 | + <filteritem type="filepath" name="harmony/doc_viewer.har" desc="项目打包文件"/> | ||
| 79 | + <filteritem type="filepath" name="example/**/*" desc="示例工程,不添加版权头"/> | ||
| 80 | + </filefilter> | ||
| 81 | + </filefilterlist> | ||
| 82 | + </oatconfig> | ||
| 83 | +</configuration> | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +BUILD_PKG_DIR=example | ||
| 3 | +BUILD_SAMPLE_DIR=example/harmony | ||
| 4 | +BUILD_THIRD_PARTY_DIR=harmony | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | +{ | ||
| 2 | + "extends": "@react-native", | ||
| 3 | + "rules": { | ||
| 4 | + "react-native/no-inline-styles": "off", | ||
| 5 | + "react/no-unstable-nested-components": "off", | ||
| 6 | + "react/react-in-jsx-scope": "off", | ||
| 7 | + "@typescript-eslint/no-unused-vars": "warn", | ||
| 8 | + "react-hooks/exhaustive-deps": "off", | ||
| 9 | + "radix": "off", | ||
| 10 | + "prettier/prettier": "warn", | ||
| 11 | + "max-lines": "off" | ||
| 12 | + } | ||
| 13 | +} | ||
| @@ -0,0 +1,71 @@ | |||
| 1 | +.husky | ||
| 2 | +bundle.harmony.js | ||
| 3 | +package-lock.json | ||
| 4 | +*.hbc | ||
| 5 | +lintCppResult.txt | ||
| 6 | + | ||
| 7 | +# --- | ||
| 8 | + | ||
| 9 | +# OSX | ||
| 10 | +# | ||
| 11 | +.DS_Store | ||
| 12 | + | ||
| 13 | +# Xcode | ||
| 14 | +# | ||
| 15 | +build/ | ||
| 16 | +*.pbxuser | ||
| 17 | +!default.pbxuser | ||
| 18 | +*.mode1v3 | ||
| 19 | +!default.mode1v3 | ||
| 20 | +*.mode2v3 | ||
| 21 | +!default.mode2v3 | ||
| 22 | +*.perspectivev3 | ||
| 23 | +!default.perspectivev3 | ||
| 24 | +xcuserdata | ||
| 25 | +*.xccheckout | ||
| 26 | +*.moved-aside | ||
| 27 | +DerivedData | ||
| 28 | +*.hmap | ||
| 29 | +*.ipa | ||
| 30 | +*.xcuserstate | ||
| 31 | + | ||
| 32 | +# Android/IntelliJ | ||
| 33 | +# | ||
| 34 | +build/ | ||
| 35 | +.idea | ||
| 36 | +.gradle | ||
| 37 | +local.properties | ||
| 38 | +*.iml | ||
| 39 | +*.hprof | ||
| 40 | +.cxx/ | ||
| 41 | +*.keystore | ||
| 42 | +!debug.keystore | ||
| 43 | +BuildProfile.ets | ||
| 44 | + | ||
| 45 | +# node.js | ||
| 46 | +# | ||
| 47 | +node_modules/ | ||
| 48 | +npm-debug.log | ||
| 49 | +yarn-error.log | ||
| 50 | + | ||
| 51 | +# fastlane | ||
| 52 | +# | ||
| 53 | +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the | ||
| 54 | +# screenshots whenever they are needed. | ||
| 55 | +# For more information about the recommended setup visit: | ||
| 56 | +# https://docs.fastlane.tools/best-practices/source-control/ | ||
| 57 | + | ||
| 58 | +**/fastlane/report.xml | ||
| 59 | +**/fastlane/Preview.html | ||
| 60 | +**/fastlane/screenshots | ||
| 61 | +**/fastlane/test_output | ||
| 62 | + | ||
| 63 | +# Bundle artifact | ||
| 64 | +*.jsbundle | ||
| 65 | + | ||
| 66 | +# Ruby / CocoaPods | ||
| 67 | +/vendor/bundle/ | ||
| 68 | + | ||
| 69 | +# Temporary files created by Metro to check the health of the file watcher | ||
| 70 | +.metro-health-check* | ||
| 71 | +*.htrace | ||
| @@ -0,0 +1 @@ | |||
| 1 | +18 | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | +module.exports = { | ||
| 2 | + arrowParens: 'avoid', | ||
| 3 | + bracketSameLine: true, | ||
| 4 | + bracketSpacing: true, | ||
| 5 | + singleQuote: true, | ||
| 6 | + trailingComma: 'all', | ||
| 7 | +}; | ||
| @@ -0,0 +1 @@ | |||
| 1 | +{} | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +module.exports = { | ||
| 2 | + presets: ['module:@react-native/babel-preset'], | ||
| 3 | + plugins: [ | ||
| 4 | + ], | ||
| 5 | +}; | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | +# it may cause some issues when building the project when switching branches | ||
| 2 | +package-lock.json | ||
| 3 | +# we add this because we want to keep the signing configs out of git | ||
| 4 | +/build-profile.json5 | ||
| 5 | + | ||
| 6 | +rnoh_modules | ||
| 7 | + | ||
| 8 | +**/oh-package-lock.json5 | ||
| 9 | +# --- | ||
| 10 | + | ||
| 11 | +/node_modules | ||
| 12 | +/local.properties | ||
| 13 | +/.idea | ||
| 14 | +**/build | ||
| 15 | +/.hvigor | ||
| 16 | +.cxx | ||
| 17 | +/.clangd | ||
| 18 | +/.clang-format | ||
| 19 | +/.clang-tidy | ||
| 20 | +/oh_modules | ||
| 21 | +hvigorw | ||
| 22 | +hvigorw.bat | ||
| 23 | +hvigor/hvigor-wrapper.js | ||
| 24 | + | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | +{ | ||
| 2 | + "app": { | ||
| 3 | + "bundleName": "com.harmony.doc.viewer.demo", | ||
| 4 | + "vendor": "example", | ||
| 5 | + "versionCode": 1000000, | ||
| 6 | + "versionName": "1.0.0", | ||
| 7 | + "icon": "$media:app_icon", | ||
| 8 | + "label": "$string:app_name" | ||
| 9 | + } | ||
| 10 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "app_name", | ||
| 5 | + "value": "Tester" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,39 @@ | |||
| 1 | +{ | ||
| 2 | + "app": { | ||
| 3 | + "products": [ | ||
| 4 | + { | ||
| 5 | + "name": 'default', | ||
| 6 | + "signingConfig": 'default', | ||
| 7 | + "compatibleSdkVersion": '5.0.0(12)', | ||
| 8 | + "runtimeOS": 'HarmonyOS' | ||
| 9 | + }, | ||
| 10 | + ], | ||
| 11 | + "buildModeSet": [ | ||
| 12 | + { | ||
| 13 | + "name": 'debug', | ||
| 14 | + }, | ||
| 15 | + { | ||
| 16 | + "name": 'release', | ||
| 17 | + }, | ||
| 18 | + ], | ||
| 19 | + "signingConfigs": [] | ||
| 20 | + }, | ||
| 21 | + "modules": [ | ||
| 22 | + { | ||
| 23 | + "name": 'entry', | ||
| 24 | + "srcPath": './entry', | ||
| 25 | + "targets": [ | ||
| 26 | + { | ||
| 27 | + "name": 'default', | ||
| 28 | + "applyToProducts": [ | ||
| 29 | + 'default' | ||
| 30 | + ], | ||
| 31 | + }, | ||
| 32 | + ], | ||
| 33 | + }, | ||
| 34 | + { | ||
| 35 | + "name": "doc_viewer", | ||
| 36 | + "srcPath": '../../harmony/doc-viewer' | ||
| 37 | + } | ||
| 38 | + ], | ||
| 39 | +} | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | +{ | ||
| 2 | + "files": ["**/*.ts", "**/*.ets"], | ||
| 3 | + "ignore": [ | ||
| 4 | + "**/ohosTest/**/*", | ||
| 5 | + "**/node_modules/**/*", | ||
| 6 | + "**/hvigorfile.ts", | ||
| 7 | + "**/node_modules/**/*", | ||
| 8 | + "**/oh_modules/**/*", | ||
| 9 | + "**/build/**/*", | ||
| 10 | + "**/.preview/**/*" | ||
| 11 | + ], | ||
| 12 | + "plugins": ["@typescript-eslint"], | ||
| 13 | + "ruleSet": [], | ||
| 14 | + "rules": { | ||
| 15 | + "@typescript-eslint/await-thenable": "warn", | ||
| 16 | + "@typescript-eslint/consistent-type-imports": "warn", | ||
| 17 | + "@typescript-eslint/explicit-function-return-type": "warn", | ||
| 18 | + "@typescript-eslint/explicit-module-boundary-types": "warn", | ||
| 19 | + "@typescript-eslint/no-dynamic-delete": "warn", | ||
| 20 | + "@typescript-eslint/no-explicit-any": "warn", | ||
| 21 | + "@typescript-eslint/no-for-in-array": "warn", | ||
| 22 | + "@typescript-eslint/no-this-alias": "warn", | ||
| 23 | + "@typescript-eslint/no-unnecessary-type-constraint": "warn", | ||
| 24 | + "@typescript-eslint/no-unsafe-argument": "warn", | ||
| 25 | + "@typescript-eslint/no-unsafe-assignment": "warn", | ||
| 26 | + "@typescript-eslint/no-unsafe-call": "warn", | ||
| 27 | + "@typescript-eslint/no-unsafe-member-access": "warn", | ||
| 28 | + "@typescript-eslint/no-unsafe-return": "warn", | ||
| 29 | + "@typescript-eslint/prefer-literal-enum-member": "warn" | ||
| 30 | + }, | ||
| 31 | + "overrides": [] | ||
| 32 | +} | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | +/node_modules | ||
| 2 | +/.preview | ||
| 3 | +/build | ||
| 4 | +/.cxx | ||
| 5 | +package-lock.json | ||
| 6 | +/oh_modules | ||
| 7 | +/assets | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | +{ | ||
| 2 | + "apiType": 'stageMode', | ||
| 3 | + "buildOption": { | ||
| 4 | + "externalNativeOptions": { | ||
| 5 | + "path": "./src/main/cpp/CMakeLists.txt", | ||
| 6 | + "arguments": "", | ||
| 7 | + "cppFlags": "-s", | ||
| 8 | + "abiFilters": [ | ||
| 9 | + "arm64-v8a", | ||
| 10 | + "x86_64" | ||
| 11 | + ] | ||
| 12 | + }, | ||
| 13 | + }, | ||
| 14 | + "targets": [ | ||
| 15 | + { | ||
| 16 | + "name": "default", | ||
| 17 | + }, | ||
| 18 | + { | ||
| 19 | + "name": "ohosTest", | ||
| 20 | + } | ||
| 21 | + ] | ||
| 22 | +} | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. | ||
| 2 | +export { hapTasks } from '@ohos/hvigor-ohos-plugin'; | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | +{ | ||
| 2 | + "license": "ISC", | ||
| 3 | + "devDependencies": {}, | ||
| 4 | + "name": "entry", | ||
| 5 | + "description": "example description", | ||
| 6 | + "version": "1.0.0", | ||
| 7 | + "dependencies": { | ||
| 8 | + "@rnoh/react-native-openharmony": "file:../../node_modules/react-native-harmony/react_native_openharmony.har", | ||
| 9 | + "@react-native-ohos/react-native-doc-viewer": "file:../../node_modules/@react-native-ohos/react-native-doc-viewer/harmony/doc_viewer.har" | ||
| 10 | + } | ||
| 11 | +} | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +jsbundle.h | ||
| 2 | +generated/ | ||
| @@ -0,0 +1,41 @@ | |||
| 1 | +project(rnapp) | ||
| 2 | +cmake_minimum_required(VERSION 3.4.1) | ||
| 3 | +set(CMAKE_SKIP_BUILD_RPATH TRUE) | ||
| 4 | +set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | ||
| 5 | +set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules") | ||
| 6 | +set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules") | ||
| 7 | +set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@rnoh/react-native-openharmony/src/main/cpp") | ||
| 8 | +set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated") | ||
| 9 | +set(LOG_VERBOSITY_LEVEL 1) | ||
| 10 | +set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments") | ||
| 11 | +set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie") | ||
| 12 | +set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules") | ||
| 13 | + | ||
| 14 | +set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use | ||
| 15 | +add_compile_definitions(WITH_HITRACE_SYSTRACE) | ||
| 16 | + | ||
| 17 | +# (VM) Define a variable and assign it to the current module's cpp directory | ||
| 18 | +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 19 | + | ||
| 20 | +# Add the Header File directory, including cpp, cpp/include, and tell cmake to find the Header Files introduced by the code here | ||
| 21 | +include_directories(${NATIVERENDER_ROOT_PATH} | ||
| 22 | + ${NATIVERENDER_ROOT_PATH}/include) | ||
| 23 | + | ||
| 24 | +add_subdirectory("${RNOH_CPP_DIR}" ./rn) | ||
| 25 | + | ||
| 26 | +# RNOH_BEGIN: manual_package_linking_1 | ||
| 27 | +add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-doc-viewer/src/main/cpp" ./doc-viewer) | ||
| 28 | +# RNOH_END: manual_package_linking_1 | ||
| 29 | + | ||
| 30 | +file(GLOB GENERATED_CPP_FILES "${CMAKE_CURRENT_SOURCE_DIR}/generated/*.cpp") # this line is needed by codegen v1 | ||
| 31 | + | ||
| 32 | +add_library(rnoh_app SHARED | ||
| 33 | + ${GENERATED_CPP_FILES} | ||
| 34 | + "./PackageProvider.cpp" | ||
| 35 | + "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp" | ||
| 36 | +) | ||
| 37 | +target_link_libraries(rnoh_app PUBLIC rnoh) | ||
| 38 | + | ||
| 39 | +# RNOH_BEGIN: manual_package_linking_2 | ||
| 40 | +target_link_libraries(rnoh_app PUBLIC rnoh_doc_viewer) | ||
| 41 | +# RNOH_END: manual_package_linking_2 | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | +#include "RNOH/PackageProvider.h" | ||
| 2 | +#include "generated/RNOHGeneratedPackage.h" | ||
| 3 | +#include "DocViewerPackage.h" | ||
| 4 | + | ||
| 5 | +using namespace rnoh; | ||
| 6 | + | ||
| 7 | +std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) | ||
| 8 | +{ | ||
| 9 | + return { | ||
| 10 | + std::make_shared<RNOHGeneratedPackage>(ctx), // generated by codegen v1 | ||
| 11 | + std::make_shared<DocViewerPackage>(ctx) | ||
| 12 | + }; | ||
| 13 | +} | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +import type {RNPackageContext, RNPackage} from '@rnoh/react-native-openharmony/ts'; | ||
| 2 | +import {DocViewPackage} from '@react-native-ohos/react-native-doc-viewer/ts'; | ||
| 3 | + | ||
| 4 | +export function createRNPackages(ctx: RNPackageContext): RNPackage[] { | ||
| 5 | + return [new DocViewPackage(ctx)]; | ||
| 6 | +} | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | +import {RNAbility} from '@rnoh/react-native-openharmony'; | ||
| 2 | +import {AbilityConstant, Want} from '@kit.AbilityKit'; | ||
| 3 | + | ||
| 4 | +export default class EntryAbility extends RNAbility { | ||
| 5 | + onCreate(want: Want) { | ||
| 6 | + super.onCreate(want) | ||
| 7 | + } | ||
| 8 | + | ||
| 9 | + getPagePath() { | ||
| 10 | + return 'pages/Index'; | ||
| 11 | + } | ||
| 12 | + | ||
| 13 | + onNewWant(want: Want, _launchParam: AbilityConstant.LaunchParam): void { | ||
| 14 | + } | ||
| 15 | +} | ||
| @@ -0,0 +1,106 @@ | |||
| 1 | +import { | ||
| 2 | + AnyJSBundleProvider, | ||
| 3 | + ComponentBuilderContext, | ||
| 4 | + FileJSBundleProvider, | ||
| 5 | + MetroJSBundleProvider, | ||
| 6 | + ResourceJSBundleProvider, | ||
| 7 | + RNApp, | ||
| 8 | + RNOHErrorDialog, | ||
| 9 | + RNOHLogger, | ||
| 10 | + TraceJSBundleProviderDecorator, | ||
| 11 | + RNOHCoreContext | ||
| 12 | +} from '@rnoh/react-native-openharmony'; | ||
| 13 | +import font from '@ohos.font'; | ||
| 14 | +import { createRNPackages } from '../RNPackagesFactory'; | ||
| 15 | + | ||
| 16 | +const arkTsComponentNames: Array<string> = [ | ||
| 17 | +]; | ||
| 18 | + | ||
| 19 | +@Builder | ||
| 20 | +export function buildCustomRNComponent(ctx: ComponentBuilderContext) { | ||
| 21 | + Stack() { | ||
| 22 | + } | ||
| 23 | + .position({x: 0, y: 0}) | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent) | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * If you want to use custom fonts, you need to register them here. | ||
| 30 | + * We should support react-native-asset to handle registering fonts automatically. | ||
| 31 | + */ | ||
| 32 | +const fonts: font.FontOptions[] = [ | ||
| 33 | + { | ||
| 34 | + familyName: 'Pacifico-Regular', | ||
| 35 | + familySrc: '/assets/fonts/Pacifico-Regular.ttf' | ||
| 36 | + }, | ||
| 37 | + { | ||
| 38 | + familyName: 'StintUltraCondensed-Regular', | ||
| 39 | + familySrc: '/assets/fonts/StintUltraCondensed-Regular.ttf' | ||
| 40 | + } | ||
| 41 | +] | ||
| 42 | + | ||
| 43 | +@Entry | ||
| 44 | +@Component | ||
| 45 | +struct Index { | ||
| 46 | + @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined | ||
| 47 | + @State shouldShow: boolean = false | ||
| 48 | + private logger!: RNOHLogger | ||
| 49 | + | ||
| 50 | + aboutToAppear() { | ||
| 51 | + this.logger = this.rnohCoreContext!.logger.clone("Index") | ||
| 52 | + const stopTracing = this.logger.clone("aboutToAppear").startTracing() | ||
| 53 | + for (const customFont of fonts) { | ||
| 54 | + font.registerFont(customFont) | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + this.shouldShow = true | ||
| 58 | + stopTracing() | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + onBackPress(): boolean | undefined { | ||
| 62 | + // NOTE: this is required since `Ability`'s `onBackPressed` function always | ||
| 63 | + // terminates or puts the app in the background, but we want Ark to ignore it completely | ||
| 64 | + // when handled by RN | ||
| 65 | + this.rnohCoreContext!.dispatchBackPress() | ||
| 66 | + return true | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + build() { | ||
| 70 | + Column() { | ||
| 71 | + if (this.rnohCoreContext && this.shouldShow) { | ||
| 72 | + if (this.rnohCoreContext?.isDebugModeEnabled) { | ||
| 73 | + RNOHErrorDialog({ ctx: this.rnohCoreContext }) | ||
| 74 | + } | ||
| 75 | + RNApp({ | ||
| 76 | + rnInstanceConfig: { | ||
| 77 | + createRNPackages, | ||
| 78 | + enableNDKTextMeasuring: true, | ||
| 79 | + enableBackgroundExecutor: false, | ||
| 80 | + enableCAPIArchitecture: true, | ||
| 81 | + arkTsComponentNames: arkTsComponentNames, | ||
| 82 | + }, | ||
| 83 | + initialProps: { "foo": "bar" } as Record<string, string>, | ||
| 84 | + appKey: "app_name", | ||
| 85 | + wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder, | ||
| 86 | + onSetUp: (rnInstance) => { | ||
| 87 | + rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP") | ||
| 88 | + }, | ||
| 89 | + jsBundleProvider: new TraceJSBundleProviderDecorator( | ||
| 90 | + new AnyJSBundleProvider([ | ||
| 91 | + new MetroJSBundleProvider(), | ||
| 92 | + // NOTE: to load the bundle from file, place it in | ||
| 93 | + // `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js` | ||
| 94 | + // on your device. The path mismatch is due to app sandboxing on HarmonyOS | ||
| 95 | + new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'), | ||
| 96 | + new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'), | ||
| 97 | + new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js') | ||
| 98 | + ]), | ||
| 99 | + this.rnohCoreContext.logger), | ||
| 100 | + }) | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + .height('100%') | ||
| 104 | + .width('100%') | ||
| 105 | + } | ||
| 106 | +} | ||
| @@ -0,0 +1,47 @@ | |||
| 1 | +{ | ||
| 2 | + "module": { | ||
| 3 | + "name": "entry", | ||
| 4 | + "type": "entry", | ||
| 5 | + "description": "$string:module_desc", | ||
| 6 | + "mainElement": "EntryAbility", | ||
| 7 | + "deviceTypes": [ | ||
| 8 | + "default" | ||
| 9 | + ], | ||
| 10 | + "deliveryWithInstall": true, | ||
| 11 | + "installationFree": false, | ||
| 12 | + "pages": "$profile:main_pages", | ||
| 13 | + "requestPermissions": [ | ||
| 14 | + { | ||
| 15 | + "name": "ohos.permission.INTERNET" | ||
| 16 | + }, | ||
| 17 | + ], | ||
| 18 | + "metadata": [ | ||
| 19 | + { | ||
| 20 | + "name": "OPTLazyForEach", | ||
| 21 | + "value": "true", | ||
| 22 | + } | ||
| 23 | + ], | ||
| 24 | + "abilities": [ | ||
| 25 | + { | ||
| 26 | + "name": "EntryAbility", | ||
| 27 | + "srcEntry": "./ets/entryability/EntryAbility.ets", | ||
| 28 | + "description": "$string:EntryAbility_desc", | ||
| 29 | + "icon": "$media:icon", | ||
| 30 | + "label": "$string:EntryAbility_label", | ||
| 31 | + "startWindowIcon": "$media:icon", | ||
| 32 | + "startWindowBackground": "$color:start_window_background", | ||
| 33 | + "visible": true, | ||
| 34 | + "skills": [ | ||
| 35 | + { | ||
| 36 | + "entities": [ | ||
| 37 | + "entity.system.home" | ||
| 38 | + ], | ||
| 39 | + "actions": [ | ||
| 40 | + "action.system.home" | ||
| 41 | + ] | ||
| 42 | + } | ||
| 43 | + ] | ||
| 44 | + } | ||
| 45 | + ] | ||
| 46 | + } | ||
| 47 | +} | ||
| @@ -0,0 +1 @@ | |||
| 1 | +rawfile/assets | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "color": [ | ||
| 3 | + { | ||
| 4 | + "name": "start_window_background", | ||
| 5 | + "value": "#FFFFFF" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "module_desc", | ||
| 5 | + "value": "module description" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "name": "EntryAbility_desc", | ||
| 9 | + "value": "description" | ||
| 10 | + }, | ||
| 11 | + { | ||
| 12 | + "name": "EntryAbility_label", | ||
| 13 | + "value": "RN Tester" | ||
| 14 | + } | ||
| 15 | + ] | ||
| 16 | +} | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +{ | ||
| 2 | + "src": [ | ||
| 3 | + "pages/Index" | ||
| 4 | + ] | ||
| 5 | +} | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | +$directoryPath = Split-Path -Parent $MyInvocation.MyCommand.Path | ||
| 2 | +$filePaths = Get-ChildItem $directoryPath -Recurse -Include *.h, *.cpp | | ||
| 3 | +Where-Object { | ||
| 4 | + $_.DirectoryName -notmatch 'third-party' -and | ||
| 5 | + $_.DirectoryName -notmatch 'patches' -and | ||
| 6 | + $_.DirectoryName -notmatch 'node_modules' -and | ||
| 7 | + $_.DirectoryName -notmatch '.cxx' -and | ||
| 8 | + $_.DirectoryName -notmatch 'build' | ||
| 9 | +} | ||
| 10 | +foreach ($filePath in $filePaths) { | ||
| 11 | + & "clang-format.exe" -style=file -i $filePath.FullName | ||
| 12 | +} | ||
| @@ -0,0 +1 @@ | |||
| 1 | +*.tgz | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | +{ | ||
| 2 | + "modelVersion": "5.0.0", | ||
| 3 | + "dependencies": { | ||
| 4 | + }, | ||
| 5 | + "execution": { | ||
| 6 | + // "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */ | ||
| 7 | + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ | ||
| 8 | + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ | ||
| 9 | + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ | ||
| 10 | + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ | ||
| 11 | + }, | ||
| 12 | + "logging": { | ||
| 13 | + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ | ||
| 14 | + }, | ||
| 15 | + "debugging": { | ||
| 16 | + "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ | ||
| 17 | + }, | ||
| 18 | + "nodeOptions": { | ||
| 19 | + // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */ | ||
| 20 | + } | ||
| 21 | +} | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. | ||
| 2 | +export { appTasks } from '@ohos/hvigor-ohos-plugin'; | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | +{ | ||
| 2 | + "modelVersion": "5.0.0", | ||
| 3 | + "license": "ISC", | ||
| 4 | + "name": "rnoh", | ||
| 5 | + "description": "example description", | ||
| 6 | + "repository": {}, | ||
| 7 | + "version": "1.0.0", | ||
| 8 | + "overrides": { | ||
| 9 | + "@rnoh/react-native-openharmony": "file:./../node_modules/react-native-harmony/react_native_openharmony.har" | ||
| 10 | + }, | ||
| 11 | + "dynamicDependencies": {} | ||
| 12 | +} | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +import {AppRegistry} from 'react-native'; | ||
| 2 | +import {name as appName} from './app.json'; | ||
| 3 | +import DocViewerExample from './src/DocViewerTest'; | ||
| 4 | + | ||
| 5 | +AppRegistry.registerComponent(appName, () => DocViewerExample); | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +/** @type {import('ts-jest').JestConfigWithTsJest} */ | ||
| 2 | +module.exports = { | ||
| 3 | + preset: 'ts-jest', | ||
| 4 | + testEnvironment: 'node', | ||
| 5 | +}; | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | +const {mergeConfig, getDefaultConfig} = require('@react-native/metro-config'); | ||
| 2 | +const {createHarmonyMetroConfig} = require('react-native-harmony/metro.config'); | ||
| 3 | + | ||
| 4 | +/** | ||
| 5 | + * @type {import("metro-config").ConfigT} | ||
| 6 | + */ | ||
| 7 | +const config = { | ||
| 8 | + transformer: { | ||
| 9 | + getTransformOptions: async () => ({ | ||
| 10 | + transform: { | ||
| 11 | + experimentalImportSupport: false, | ||
| 12 | + inlineRequires: true, | ||
| 13 | + }, | ||
| 14 | + }), | ||
| 15 | + }, | ||
| 16 | +}; | ||
| 17 | + | ||
| 18 | +module.exports = mergeConfig( | ||
| 19 | + getDefaultConfig(__dirname), | ||
| 20 | + createHarmonyMetroConfig({ | ||
| 21 | + reactNativeHarmonyPackageName: 'react-native-harmony', | ||
| 22 | + }), | ||
| 23 | + config, | ||
| 24 | +); | ||
| @@ -0,0 +1,58 @@ | |||
| 1 | +{ | ||
| 2 | + "name": "react-native-harmony-tester", | ||
| 3 | + "version": "1.0.0", | ||
| 4 | + "private": true, | ||
| 5 | + "scripts": { | ||
| 6 | + "i": "cd ../ && npm i && npm run pack && cd ./example && npm i", | ||
| 7 | + "reStart": "npm run install:pkg && npm run codegen && hdc rport tcp:8081 tcp:8081 && react-native start", | ||
| 8 | + "start": "hdc rport tcp:8081 tcp:8081 && react-native start", | ||
| 9 | + "codegen": "react-native codegen-harmony --rnoh-module-path ./harmony/entry/oh_modules/@rnoh/react-native-openharmony", | ||
| 10 | + "pack:pkg": "cd ../ && npm pack && cd ./example", | ||
| 11 | + "install:pkg": "npm uninstall @react-native-ohos/react-native-doc-viewer && npm run pack:pkg && npm i @react-native-ohos/react-native-doc-viewer@file:../react-native-ohos-react-native-doc-viewer-2.8.1-beta.1.tgz", | ||
| 12 | + "dev": "npm run codegen && react-native bundle-harmony --dev --minify=false", | ||
| 13 | + "prod": "npm run codegen && react-native bundle-harmony --dev=false --minify=true", | ||
| 14 | + "postinstall": "node ./scripts/create-build-profile", | ||
| 15 | + "fast-install-project": "cd ../ && npm i --force && npm pack && rm -r node_modules && cd ./example && npm i --force", | ||
| 16 | + "fast:pkg": "npm run fast-install-project && npm run dev" | ||
| 17 | + }, | ||
| 18 | + "dependencies": { | ||
| 19 | + "@react-native-oh/react-native-harmony": "0.77.18-1", | ||
| 20 | + "@react-native-ohos/react-native-doc-viewer": "file:../react-native-ohos-react-native-doc-viewer-2.8.1-beta.1.tgz", | ||
| 21 | + "react": "18.3.1", | ||
| 22 | + "react-native": "0.77.1", | ||
| 23 | + "react-native-harmony": "npm:@react-native-oh/react-native-harmony@0.77.18-1" | ||
| 24 | + }, | ||
| 25 | + "devDependencies": { | ||
| 26 | + "@babel/core": "^7.25.2", | ||
| 27 | + "@babel/preset-env": "^7.25.3", | ||
| 28 | + "@babel/runtime": "^7.25.0", | ||
| 29 | + "@react-native-community/cli": "15.0.1", | ||
| 30 | + "@react-native-community/eslint-config": "^3.2.0", | ||
| 31 | + "@react-native-oh/react-native-harmony-cli": "0.77.18-1", | ||
| 32 | + "@react-native/babel-preset": "0.77.1", | ||
| 33 | + "@react-native/eslint-config": "0.77.1", | ||
| 34 | + "@react-native/metro-config": "^0.77.1", | ||
| 35 | + "@react-native/typescript-config": "0.77.1", | ||
| 36 | + "@rnoh/react-native-harmony-cli": "npm:@react-native-oh/react-native-harmony-cli@0.77.18-1", | ||
| 37 | + "@tsconfig/react-native": "^3.0.0", | ||
| 38 | + "@types/jest": "^29.5.13", | ||
| 39 | + "@types/react": "^18.2.6", | ||
| 40 | + "@types/react-test-renderer": "^18.0.0", | ||
| 41 | + "babel-jest": "^29.6.3", | ||
| 42 | + "eslint": "^8.19.0", | ||
| 43 | + "jest": "^29.7.0", | ||
| 44 | + "metro-react-native-babel-preset": "0.76.8", | ||
| 45 | + "prettier": "2.8.8", | ||
| 46 | + "react-test-renderer": "18.3.1", | ||
| 47 | + "typescript": "5.5.4" | ||
| 48 | + }, | ||
| 49 | + "overrides": { | ||
| 50 | + "@react-native-community/cli": "15.0.1" | ||
| 51 | + }, | ||
| 52 | + "resolutions": { | ||
| 53 | + "@react-native-community/cli": "15.0.1" | ||
| 54 | + }, | ||
| 55 | + "engines": { | ||
| 56 | + "node": ">=18" | ||
| 57 | + } | ||
| 58 | +} | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | +module.exports = { | ||
| 2 | + project: { | ||
| 3 | + }, | ||
| 4 | + assets: ['./assets/fonts/'], | ||
| 5 | +}; | ||
| @@ -0,0 +1,39 @@ | |||
| 1 | +const fs = require('fs'); | ||
| 2 | +const JSON5 = require('json5'); | ||
| 3 | +const path = require('path'); | ||
| 4 | + | ||
| 5 | +const templatePath = path.join( | ||
| 6 | + __dirname, | ||
| 7 | + '..', | ||
| 8 | + 'harmony', | ||
| 9 | + 'build-profile.template.json5', | ||
| 10 | +); | ||
| 11 | +const existingProfilePath = path.join( | ||
| 12 | + __dirname, | ||
| 13 | + '..', | ||
| 14 | + 'harmony', | ||
| 15 | + 'build-profile.json5', | ||
| 16 | +); | ||
| 17 | + | ||
| 18 | +if (fs.existsSync(existingProfilePath)) { | ||
| 19 | + let existingProfile = JSON5.parse( | ||
| 20 | + fs.readFileSync(existingProfilePath, 'utf-8'), | ||
| 21 | + ); | ||
| 22 | + let template = JSON5.parse(fs.readFileSync(templatePath, 'utf-8')); | ||
| 23 | + let signingConfigs = | ||
| 24 | + existingProfile.app && existingProfile.app.signingConfigs; | ||
| 25 | + | ||
| 26 | + existingProfile = {...template}; | ||
| 27 | + | ||
| 28 | + if (signingConfigs) { | ||
| 29 | + existingProfile.app.signingConfigs = signingConfigs; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + fs.writeFileSync( | ||
| 33 | + existingProfilePath, | ||
| 34 | + JSON5.stringify(existingProfile, null, 2), | ||
| 35 | + ); | ||
| 36 | +} else { | ||
| 37 | + // File doesn't exist, create a copy from the template | ||
| 38 | + fs.copyFileSync(templatePath, existingProfilePath); | ||
| 39 | +} | ||
| @@ -0,0 +1,140 @@ | |||
| 1 | +import React from 'react'; | ||
| 2 | +import {ScrollView, StyleSheet, View, Button, Text} from 'react-native'; | ||
| 3 | +import OpenFile from '@react-native-ohos/react-native-doc-viewer'; | ||
| 4 | + | ||
| 5 | +interface FileInfo { | ||
| 6 | + url?: string; | ||
| 7 | + fileName?: string; | ||
| 8 | + fileType?: string; | ||
| 9 | + cache?: boolean; | ||
| 10 | + base64?: string; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +const testUrls = { | ||
| 14 | + pdf: 'https://filesamples.com/samples/document/pdf/sample3.pdf', | ||
| 15 | + mp3: 'https://filesamples.com/samples/audio/mp3/sample3.mp3', | ||
| 16 | + mp4: 'https://filesamples.com/samples/video/mp4/sample_960x400_ocean_with_audio.mp4', | ||
| 17 | + doc: 'https://filesamples.com/samples/document/doc/sample1.doc', | ||
| 18 | + jpeg: 'https://filesamples.com/samples/image/jpeg/sample_1280x853.jpeg', | ||
| 19 | + xlsx: 'https://filesamples.com/samples/document/xlsx/sample1.xlsx', | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +const base64Png = | ||
| 23 | + 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA4pOS9AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAEUlEQVQoz2P8z0AZYKQWGBgYAMXeAT3H9Lh1AAAAAElFTkSuQmCC'; | ||
| 24 | + | ||
| 25 | +export function DocViewerExample() { | ||
| 26 | + const [status, setStatus] = React.useState('idle'); | ||
| 27 | + | ||
| 28 | + const openDoc = (config: FileInfo) => { | ||
| 29 | + setStatus(`openDoc ${config.fileName ?? ''}`); | ||
| 30 | + OpenFile.openDoc([config], (err: string) => { | ||
| 31 | + setStatus(err ? `openDoc err: ${err}` : 'openDoc success'); | ||
| 32 | + }); | ||
| 33 | + }; | ||
| 34 | + | ||
| 35 | + const openDocBinaryinUrl = (config: FileInfo) => { | ||
| 36 | + setStatus(`openDocBinaryinUrl ${config.fileName ?? ''}`); | ||
| 37 | + OpenFile.openDocBinaryinUrl([config], (err: string) => { | ||
| 38 | + setStatus(err ? `openDocBinaryinUrl err: ${err}` : 'openDocBinaryinUrl success'); | ||
| 39 | + }); | ||
| 40 | + }; | ||
| 41 | + | ||
| 42 | + const openDocb64 = (config: FileInfo) => { | ||
| 43 | + setStatus('openDocb64'); | ||
| 44 | + OpenFile.openDocb64([config], (err: string) => { | ||
| 45 | + setStatus(err ? `openDocb64 err: ${err}` : 'openDocb64 success'); | ||
| 46 | + }); | ||
| 47 | + }; | ||
| 48 | + | ||
| 49 | + return ( | ||
| 50 | + <View style={styles.container}> | ||
| 51 | + <Text style={styles.title}>react-native-doc-viewer tester</Text> | ||
| 52 | + <Text style={styles.status}>status: {status}</Text> | ||
| 53 | + <ScrollView> | ||
| 54 | + <View style={styles.item}> | ||
| 55 | + <Button | ||
| 56 | + title="Open PDF with openDoc" | ||
| 57 | + onPress={() => | ||
| 58 | + openDoc({url: testUrls.pdf, fileName: 'sample.pdf', fileType: 'pdf', cache: true}) | ||
| 59 | + } | ||
| 60 | + /> | ||
| 61 | + </View> | ||
| 62 | + <View style={styles.item}> | ||
| 63 | + <Button | ||
| 64 | + title="Open PDF with openDoc (no cache)" | ||
| 65 | + onPress={() => | ||
| 66 | + openDoc({url: testUrls.pdf, fileName: 'sample.pdf', fileType: 'pdf', cache: false}) | ||
| 67 | + } | ||
| 68 | + /> | ||
| 69 | + </View> | ||
| 70 | + <View style={styles.item}> | ||
| 71 | + <Button | ||
| 72 | + title="Open MP4 with openDoc" | ||
| 73 | + onPress={() => | ||
| 74 | + openDoc({url: testUrls.mp4, fileName: 'sample.mp4', fileType: 'mp4', cache: true}) | ||
| 75 | + } | ||
| 76 | + /> | ||
| 77 | + </View> | ||
| 78 | + <View style={styles.item}> | ||
| 79 | + <Button | ||
| 80 | + title="Open MP3 with openDoc" | ||
| 81 | + onPress={() => | ||
| 82 | + openDoc({url: testUrls.mp3, fileName: 'sample.mp3', fileType: 'mp3', cache: true}) | ||
| 83 | + } | ||
| 84 | + /> | ||
| 85 | + </View> | ||
| 86 | + <View style={styles.item}> | ||
| 87 | + <Button | ||
| 88 | + title="Open DOC with openDoc" | ||
| 89 | + onPress={() => | ||
| 90 | + openDoc({url: testUrls.doc, fileName: 'sample.doc', fileType: 'doc', cache: true}) | ||
| 91 | + } | ||
| 92 | + /> | ||
| 93 | + </View> | ||
| 94 | + <View style={styles.item}> | ||
| 95 | + <Button | ||
| 96 | + title="Open XLSX with openDoc" | ||
| 97 | + onPress={() => | ||
| 98 | + openDoc({url: testUrls.xlsx, fileName: 'sample.xlsx', fileType: 'xlsx', cache: true}) | ||
| 99 | + } | ||
| 100 | + /> | ||
| 101 | + </View> | ||
| 102 | + <View style={styles.item}> | ||
| 103 | + <Button | ||
| 104 | + title="Open JPEG with openDocBinaryinUrl" | ||
| 105 | + onPress={() => | ||
| 106 | + openDocBinaryinUrl({ | ||
| 107 | + url: testUrls.jpeg, | ||
| 108 | + fileName: 'sample.jpeg', | ||
| 109 | + fileType: 'jpeg', | ||
| 110 | + cache: true, | ||
| 111 | + }) | ||
| 112 | + } | ||
| 113 | + /> | ||
| 114 | + </View> | ||
| 115 | + <View style={styles.item}> | ||
| 116 | + <Button | ||
| 117 | + title="Open base64 PNG with openDocb64" | ||
| 118 | + onPress={() => | ||
| 119 | + openDocb64({ | ||
| 120 | + base64: base64Png, | ||
| 121 | + fileName: 'sample.png', | ||
| 122 | + fileType: 'png', | ||
| 123 | + cache: false, | ||
| 124 | + }) | ||
| 125 | + } | ||
| 126 | + /> | ||
| 127 | + </View> | ||
| 128 | + </ScrollView> | ||
| 129 | + </View> | ||
| 130 | + ); | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +const styles = StyleSheet.create({ | ||
| 134 | + container: {flex: 1, backgroundColor: '#fff', padding: 16}, | ||
| 135 | + title: {fontSize: 18, fontWeight: 'bold', marginBottom: 8}, | ||
| 136 | + status: {fontSize: 12, color: '#666', marginBottom: 12}, | ||
| 137 | + item: {marginBottom: 12}, | ||
| 138 | +}); | ||
| 139 | + | ||
| 140 | +export default DocViewerExample; | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | +{ | ||
| 2 | + "extends": "@react-native/typescript-config/tsconfig.json", | ||
| 3 | + "compilerOptions": { | ||
| 4 | + "jsx": "react-native", | ||
| 5 | + "paths": { | ||
| 6 | + "react-native": [ | ||
| 7 | + "./node_modules/react-native-harmony" | ||
| 8 | + ], | ||
| 9 | + }, | ||
| 10 | + "skipLibCheck": true, | ||
| 11 | + }, | ||
| 12 | + "exclude": [ | ||
| 13 | + "harmony" | ||
| 14 | + ] | ||
| 15 | +} | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | export default class BuildProfile { | 1 | export default class BuildProfile { |
| 2 | - static readonly HAR_VERSION = '2.7.9-rc.1'; | 2 | + static readonly HAR_VERSION = '2.8.1-beta.1'; |
| 3 | static readonly BUILD_MODE_NAME = 'debug'; | 3 | static readonly BUILD_MODE_NAME = 'debug'; |
| 4 | static readonly DEBUG = true; | 4 | static readonly DEBUG = true; |
| 5 | static readonly TARGET_NAME = 'default'; | 5 | static readonly TARGET_NAME = 'default'; |
| @@ -1,6 +1,6 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "@react-native-ohos/react-native-doc-viewer", | 2 | "name": "@react-native-ohos/react-native-doc-viewer", |
| 3 | - "version": "2.8.0", | 3 | + "version": "2.8.1-beta.1", |
| 4 | type: 'module', | 4 | type: 'module', |
| 5 | dependencies: { | 5 | dependencies: { |
| 6 | "@rnoh/react-native-openharmony": 'file:../react_native_openharmony' | 6 | "@rnoh/react-native-openharmony": 'file:../react_native_openharmony' |
| @@ -75,6 +75,6 @@ const mimeMap = { | |||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | export function getMimeType(fileType: string) { | 77 | export function getMimeType(fileType: string) { |
| 78 | - fileType = fileType.toLowerCase() | 78 | + fileType = typeof fileType === 'string' ? fileType.toLowerCase() : '' |
| 79 | return mimeMap[fileType] || mimeMap['pdf'] | 79 | return mimeMap[fileType] || mimeMap['pdf'] |
| 80 | } | 80 | } |
| @@ -46,6 +46,10 @@ export class DocViewTurboModule extends TurboModule{ | |||
| 46 | if (base64 && fileName && fileType) { | 46 | if (base64 && fileName && fileType) { |
| 47 | try{ | 47 | try{ |
| 48 | const filePath = this.getFilePath(fileName) | 48 | const filePath = this.getFilePath(fileName) |
| 49 | + if (!filePath) { | ||
| 50 | + callback(`invalid fileName:${fileName}`) | ||
| 51 | + return | ||
| 52 | + } | ||
| 49 | if (cache) { | 53 | if (cache) { |
| 50 | Log.debug(`try to use cache base64 file`) | 54 | Log.debug(`try to use cache base64 file`) |
| 51 | this.useCache(fileType, '', fileName, callback, async () => { | 55 | this.useCache(fileType, '', fileName, callback, async () => { |
| @@ -99,23 +103,27 @@ export class DocViewTurboModule extends TurboModule{ | |||
| 99 | } | 103 | } |
| 100 | } | 104 | } |
| 101 | getFilePath(fileName: string, url?: string) { | 105 | getFilePath(fileName: string, url?: string) { |
| 102 | - const context = this.ctx.uiAbilityContext | 106 | + let name = fileName ?? '' |
| 103 | - let filedDir = this.tempDir | 107 | + if (!name && url) { |
| 104 | - if (fileName) { | 108 | + name = url.split('/').pop() ?? '' |
| 105 | - return `${filedDir}/${fileName}` | ||
| 106 | } | 109 | } |
| 107 | - if (url) { | 110 | + name = name.split('?')[0].split('#')[0] |
| 108 | - const urlSplit = url?.split('/') | 111 | + name = name.split('/').pop() ?? '' |
| 109 | - const name = urlSplit[urlSplit.length - 1] | 112 | + name = name.split('\\').pop() ?? '' |
| 110 | - Log.debug(`getFilePath name:${name}`) | 113 | + if (!name || name === '.' || name === '..') { |
| 111 | - const filePath = filedDir + `/${name}` | 114 | + Log.debug(`getFilePath invalid fileName:${JSON.stringify(fileName)}, url:${url}`) |
| 112 | - return filePath | 115 | + return '' |
| 113 | } | 116 | } |
| 114 | - return '' | 117 | + Log.debug(`getFilePath name:${name}`) |
| 118 | + return `${this.tempDir}/${name}` | ||
| 115 | } | 119 | } |
| 116 | async useCache(fileType: string, url: string, fileName: string, callback: Function, notExistsFn?: Function) { | 120 | async useCache(fileType: string, url: string, fileName: string, callback: Function, notExistsFn?: Function) { |
| 117 | Log.debug(`useCache start`) | 121 | Log.debug(`useCache start`) |
| 118 | const filePath = this.getFilePath(fileName, url) | 122 | const filePath = this.getFilePath(fileName, url) |
| 123 | + if (!filePath) { | ||
| 124 | + callback(`invalid fileName:${fileName}`) | ||
| 125 | + return | ||
| 126 | + } | ||
| 119 | const isExists = await fs.access(filePath) | 127 | const isExists = await fs.access(filePath) |
| 120 | if (isExists) { | 128 | if (isExists) { |
| 121 | Log.debug(`useCache isExists:${filePath}`) | 129 | Log.debug(`useCache isExists:${filePath}`) |
| @@ -140,43 +148,61 @@ export class DocViewTurboModule extends TurboModule{ | |||
| 140 | Log.debug(`removeFile err:${JSON.stringify(err)}`) | 148 | Log.debug(`removeFile err:${JSON.stringify(err)}`) |
| 141 | } | 149 | } |
| 142 | } | 150 | } |
| 151 | + normalizeUrl(url: string): string { | ||
| 152 | + const idx = url.indexOf('://'); | ||
| 153 | + if (idx > 0) { | ||
| 154 | + return `${url.substring(0, idx).toLowerCase()}://${url.substring(idx + 3)}`; | ||
| 155 | + } | ||
| 156 | + return url; | ||
| 157 | + } | ||
| 143 | async download(url: string, fileType: string, fileName: string, callback: Function) { | 158 | async download(url: string, fileType: string, fileName: string, callback: Function) { |
| 144 | - Log.debug(`download start url:${url}`) | 159 | + url = this.normalizeUrl(url); |
| 145 | - const filePath = this.getFilePath(fileName, url) | 160 | + Log.debug(`download start url:${url}`); |
| 146 | - this.removeFile(filePath) | 161 | + const filePath = this.getFilePath(fileName, url); |
| 147 | - const context = this.ctx.uiAbilityContext | 162 | + if (!filePath) { |
| 148 | - try{ | 163 | + callback(`invalid fileName:${fileName}`); |
| 149 | - request.downloadFile(context, { | 164 | + return; |
| 165 | + } | ||
| 166 | + await this.removeFile(filePath); | ||
| 167 | + const context = this.ctx.uiAbilityContext; | ||
| 168 | + try { | ||
| 169 | + const downloadTask = await request.downloadFile(context, { | ||
| 150 | url, | 170 | url, |
| 151 | filePath | 171 | filePath |
| 152 | - }).then(downloadTask => { | 172 | + }); |
| 153 | - Log.debug(`downloadTask start`) | 173 | + Log.debug(`downloadTask start`); |
| 154 | - downloadTask.on('complete', () => { | 174 | + this.watchDownloadTask(downloadTask, filePath, fileType, fileName, callback); |
| 155 | - Log.debug(`download complete:${fileName}`) | ||
| 156 | - this.shareFile(filePath, fileType, callback) | ||
| 157 | - }) | ||
| 158 | - downloadTask.on('fail', () => { | ||
| 159 | - Log.debug(`download fail:${fileName}`) | ||
| 160 | - this.removeFile(filePath) | ||
| 161 | - callback(`download fail`) | ||
| 162 | - }) | ||
| 163 | - }).catch(err => { | ||
| 164 | - Log.debug(`Invoke catch downloadTask failed:${JSON.stringify(err)}`) | ||
| 165 | - }) | ||
| 166 | } catch (err) { | 175 | } catch (err) { |
| 167 | - Log.debug(`Invoke catch downloadTask failed:${JSON.stringify(err)}`) | 176 | + Log.debug(`Invoke catch downloadTask failed:${JSON.stringify(err)}`); |
| 168 | if (err.code === 13400002) { | 177 | if (err.code === 13400002) { |
| 169 | - Log.debug(`file is exists:${fileName}`) | 178 | + Log.debug(`file is exists:${fileName}`); |
| 170 | - this.shareFile(filePath, fileType, callback) | 179 | + this.shareFile(filePath, fileType, callback); |
| 171 | } else { | 180 | } else { |
| 172 | - callback(`download fail`) | 181 | + callback(`download fail`); |
| 173 | } | 182 | } |
| 174 | } | 183 | } |
| 175 | } | 184 | } |
| 185 | + | ||
| 186 | + watchDownloadTask(downloadTask: request.DownloadTask, filePath: string, fileType: string, fileName: string, callback: Function) { | ||
| 187 | + downloadTask.on('complete', () => { | ||
| 188 | + Log.debug(`download complete:${fileName}`); | ||
| 189 | + this.shareFile(filePath, fileType, callback); | ||
| 190 | + }); | ||
| 191 | + downloadTask.on('fail', (err: number) => { | ||
| 192 | + Log.debug(`download fail:${fileName}, code:${err}`); | ||
| 193 | + this.removeFile(filePath); | ||
【AI-Review】【一般】【基础代码问题】【稳定性问题】fail 回调中 removeFile 未 await 导致残留文件被误共享 ● 问题:watchDownloadTask 方法的 fail 回调(turborModules.ts:193)调用 ● 影响:JS 侧收到下载失败回调后,若使用相同 fileName 且 cache=true 再次调用 openDoc/openDocBinaryinUrl(turborModules.ts:89-90),会进入 useCache(turborModules.ts:120)。useCache 执行 ● 建议:将 fail 回调改为 async 函数并 await removeFile:
downloadTask.on('fail', async (err: number) => {
Log.debug( ![]() ![]() 【AI-Review】【严重】【基础代码问题】【稳定性问题】watchDownloadTask 的 fail 回调中 removeFile 未 await,callback 在文件清理完成前发出 ● 问题:在 watchDownloadTask 方法(turborModules.ts:191-195)的 fail 回调中,第193行 ● 影响:严重。当 cache=true 场景下下载失败后用户重试时,重试流程会进入 useCache(turborModules.ts:120-139)的 ● 建议:将 fail 回调改为 async 并 await removeFile,确保文件清理完成后再通知 JS 侧:
downloadTask.on('fail', async (err: number) => {
Log.debug( ![]() ![]() | |||
| 194 | + callback(`download fail, code:${err}`); | ||
| 195 | + }); | ||
| 196 | + } | ||
| 176 | shareFile(filePath: string, fileType: string, callback: Function) { | 197 | shareFile(filePath: string, fileType: string, callback: Function) { |
| 177 | - const uri = fileUri.getUriFromPath(filePath) | 198 | + try { |
| 178 | - Log.debug(`shareFile uri: ${uri}, filePath: ${filePath}`) | 199 | + const uri = fileUri.getUriFromPath(filePath) |
| 179 | - this.start(uri, fileType, callback) | 200 | + Log.debug(`shareFile uri: ${uri}, filePath: ${filePath}`) |
| 201 | + this.start(uri, fileType, callback) | ||
| 202 | + } catch (e) { | ||
| 203 | + Log.debug(`shareFile err:${JSON.stringify(e)}`) | ||
| 204 | + callback(`shareFile err:${JSON.stringify(e)}`) | ||
| 205 | + } | ||
| 180 | } | 206 | } |
| 181 | start(uri: string, fileType: string, callback: Function) { | 207 | start(uri: string, fileType: string, callback: Function) { |
| 182 | const mimeType = getMimeType(fileType) | 208 | const mimeType = getMimeType(fileType) |
| @@ -1,6 +1,6 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "@react-native-ohos/react-native-doc-viewer", | 2 | "name": "@react-native-ohos/react-native-doc-viewer", |
| 3 | - "version": "2.8.0", | 3 | + "version": "2.8.1-beta.1", |
| 4 | "description": "React Native Native Module Bridge Quicklock Document Viewer for IOS + Android supports pdf, png, jpg, xls, ppt, doc, docx, pptx, xlx + Video Player mp4 supported ", | 4 | "description": "React Native Native Module Bridge Quicklock Document Viewer for IOS + Android supports pdf, png, jpg, xls, ppt, doc, docx, pptx, xlx + Video Player mp4 supported ", |
| 5 | "main": "lib/commonjs/index", | 5 | "main": "lib/commonjs/index", |
| 6 | "scripts": { | 6 | "scripts": { |


OAT和example不能忽略