expo-harmony-toolkit 1.9.2 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -9,7 +9,7 @@
9
9
  <p>
10
10
  <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/actions/workflows/ci.yml"><img alt="Checks" src="https://img.shields.io/badge/checks-passing-16a34a?style=flat-square&logo=githubactions&logoColor=white"></a>
11
11
  <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square"></a>
12
- <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.9.2-111827?style=flat-square"></a>
12
+ <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.10.0-111827?style=flat-square"></a>
13
13
  <a href="./docs/support-matrix.md"><img alt="Matrix" src="https://img.shields.io/badge/matrix-expo55--rnoh082--ui--stack-2563eb?style=flat-square"></a>
14
14
  <img alt="Input" src="https://img.shields.io/badge/input-Managed%2FCNG%20%2B%20bare%20intake-059669?style=flat-square">
15
15
  </p>
@@ -24,7 +24,7 @@
24
24
  </div>
25
25
 
26
26
  > [!IMPORTANT]
27
- > `v1.9.2` keeps the `v1.9.1` build-hap security baseline and brings `@react-native-async-storage/async-storage`, `react-native-screens`, and `react-native-safe-area-context` into Third-party Native Wave A formal experimental onboarding. The public promise remains tighter: `latest` only carries fully accepted `verified` capabilities, and Wave A does not widen the current `verified` boundary.
27
+ > `v1.10.0` freezes Any-project Intake: any Expo project entering `doctor` should receive a `coverageProfile`, explicit `gapCategory`, and ordered `nextActions`. The public promise remains tighter: `latest` only carries fully accepted `verified` capabilities; v1.10.0 is not a verified expansion and does not promise reliable packaging for catalog-out projects.
28
28
 
29
29
  > [!TIP]
30
30
  > The two validated `@react-native-oh-tpl/*` adapters in the public matrix are currently consumed via exact Git URLs and commits. For repository development and the official UI-stack sample, prefer `pnpm install --ignore-scripts` so adapter prepare hooks do not fail on private upstream resources.
@@ -48,13 +48,13 @@
48
48
  <!-- GENERATED:readme-current-status:start -->
49
49
  | Item | Status |
50
50
  | --- | --- |
51
- | Current version | `v1.9.2` |
51
+ | Current version | `v1.10.0` |
52
52
  | Support model | `verified + preview + experimental` |
53
53
  | Public `verified` matrix | `expo55-rnoh082-ui-stack` |
54
- | Supported input | Managed/CNG Expo projects; bare workflow intake baseline |
54
+ | Supported input | Managed/CNG Expo projects; bare and catalog-out intake classification |
55
55
  | `verified` JS/UI capabilities | `expo-router`, `expo-linking`, `expo-constants`, `react-native-reanimated`, `react-native-svg` |
56
56
  | `preview` native capabilities | `expo-file-system`, `expo-image-picker`, `expo-location`, `expo-camera`, `expo-secure-store`, `expo-asset`, `expo-device`, `expo-clipboard`, `expo-haptics` |
57
- | `experimental` capabilities | `expo-notifications`, `react-native-gesture-handler`, `@react-native-async-storage/async-storage`, `react-native-screens`, `react-native-safe-area-context` |
57
+ | `experimental` capabilities | `expo-notifications`, `react-native-gesture-handler`, `@react-native-async-storage/async-storage`, `react-native-screens`, `react-native-safe-area-context`, `react-native-webview`, `jpush-react-native`, `expo-media-library`, `lottie-react-native`, `@shopify/react-native-skia` |
58
58
  | Release tracks | `latest` = fully accepted `verified` only; `next` = preview fast track |
59
59
  | Capability telemetry | `runtimeMode` + `evidence(...)` + `evidenceSource(...)` + `coverageProfile` + `nextActions` |
60
60
  | Build path | `doctor -> init -> bundle -> build-hap` |
@@ -72,6 +72,7 @@
72
72
  - `expo-notifications`
73
73
  - `react-native-gesture-handler` remains a formal experimental slice
74
74
  - `@react-native-async-storage/async-storage`, `react-native-screens`, and `react-native-safe-area-context` remain Wave A experimental onboarding
75
+ - `react-native-webview`, JPush runtime, `expo-media-library`, `lottie-react-native`, and `@shopify/react-native-skia` remain Wave B experimental onboarding
75
76
  - multiple public matrices
76
77
 
77
78
  </details>
@@ -177,7 +178,7 @@ Common decision points:
177
178
  <!-- GENERATED:readme-support-matrix:start -->
178
179
  - `verified`: the only public matrix remains `expo55-rnoh082-ui-stack`
179
180
  - `preview`: `expo-file-system`, `expo-image-picker`, `expo-location`, `expo-camera`, `expo-secure-store`, `expo-asset`, `expo-device`, `expo-clipboard`, `expo-haptics`
180
- - `experimental`: `expo-notifications`, `react-native-gesture-handler`, `@react-native-async-storage/async-storage`, `react-native-screens`, `react-native-safe-area-context`
181
+ - `experimental`: `expo-notifications`, `react-native-gesture-handler`, `@react-native-async-storage/async-storage`, `react-native-screens`, `react-native-safe-area-context`, `react-native-webview`, `jpush-react-native`, `expo-media-library`, `lottie-react-native`, `@shopify/react-native-skia`
181
182
 
182
183
  `doctor --strict` still means `verified` only. `doctor --target-tier preview` allows the same runtime matrix plus preview-tier capabilities, but that does not promote them into the formal public promise.
183
184
 
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  <p>
10
10
  <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/actions/workflows/ci.yml"><img alt="Checks" src="https://img.shields.io/badge/checks-passing-16a34a?style=flat-square&logo=githubactions&logoColor=white"></a>
11
11
  <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square"></a>
12
- <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.9.2-111827?style=flat-square"></a>
12
+ <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.10.0-111827?style=flat-square"></a>
13
13
  <a href="./docs/support-matrix.md"><img alt="Matrix" src="https://img.shields.io/badge/matrix-expo55--rnoh082--ui--stack-2563eb?style=flat-square"></a>
14
14
  <img alt="Input" src="https://img.shields.io/badge/input-Managed%2FCNG%20%2B%20bare%20intake-059669?style=flat-square">
15
15
  </p>
@@ -24,7 +24,7 @@
24
24
  </div>
25
25
 
26
26
  > [!IMPORTANT]
27
- > `v1.9.2` 延续 `v1.9.1` build-hap 安全基线,并把 `@react-native-async-storage/async-storage`、`react-native-screens`、`react-native-safe-area-context` 纳入 Third-party Native Wave A formal experimental onboarding。当前公开承诺仍然收紧为:`latest` 只承诺完整验收的 `verified` 能力,Wave A 不放宽当前 `verified` 边界。
27
+ > `v1.10.0` 冻结 Any-project Intake:任何 Expo 项目进入 `doctor` 后都应得到 `coverageProfile`、明确 `gapCategory` 与有序 `nextActions`。当前公开承诺仍然收紧为:`latest` 只承诺完整验收的 `verified` 能力;v1.10.0 不是 verified 扩容,也不承诺 catalog 外项目都能可靠打包。
28
28
 
29
29
  > [!TIP]
30
30
  > 由于当前公开矩阵内的两套 `@react-native-oh-tpl/*` adapter 依赖以 Git URL + exact commit 形式接入,仓库开发和官方 UI-stack sample 推荐使用 `pnpm install --ignore-scripts`,避免 Git adapter 在 prepare 阶段拉取私有资源而中断安装。
@@ -48,13 +48,13 @@
48
48
  <!-- GENERATED:readme-current-status:start -->
49
49
  | 项目 | 说明 |
50
50
  | --- | --- |
51
- | 当前版本 | `v1.9.2` |
51
+ | 当前版本 | `v1.10.0` |
52
52
  | 支持模型 | `verified + preview + experimental` |
53
53
  | 唯一 `verified` 公开矩阵 | `expo55-rnoh082-ui-stack` |
54
- | 输入范围 | Managed/CNG Expo 项目;bare workflow intake baseline |
54
+ | 输入范围 | Managed/CNG Expo 项目;bare catalog 外项目 intake 分类 |
55
55
  | `verified` JS/UI 能力 | `expo-router`、`expo-linking`、`expo-constants`、`react-native-reanimated`、`react-native-svg` |
56
56
  | `preview` 原生能力 | `expo-file-system`、`expo-image-picker`、`expo-location`、`expo-camera`、`expo-secure-store`、`expo-asset`、`expo-device`、`expo-clipboard`、`expo-haptics` |
57
- | `experimental` 能力 | `expo-notifications`、`react-native-gesture-handler`、`@react-native-async-storage/async-storage`、`react-native-screens`、`react-native-safe-area-context` |
57
+ | `experimental` 能力 | `expo-notifications`、`react-native-gesture-handler`、`@react-native-async-storage/async-storage`、`react-native-screens`、`react-native-safe-area-context`、`react-native-webview`、`jpush-react-native`、`expo-media-library`、`lottie-react-native`、`@shopify/react-native-skia` |
58
58
  | 发布轨 | `latest` = fully accepted verified only;`next` = preview fast track |
59
59
  | capability 遥测 | `runtimeMode` + `evidence(...)` + `evidenceSource(...)` + `coverageProfile` + `nextActions` |
60
60
  | 构建链 | `doctor -> init -> bundle -> build-hap` |
@@ -72,6 +72,7 @@
72
72
  - `expo-notifications`
73
73
  - `react-native-gesture-handler` 仍只属于 formal experimental slice
74
74
  - `@react-native-async-storage/async-storage`、`react-native-screens`、`react-native-safe-area-context` 仍只属于 Wave A experimental onboarding
75
+ - `react-native-webview`、JPush runtime、`expo-media-library`、`lottie-react-native`、`@shopify/react-native-skia` 仍只属于 Wave B experimental onboarding
75
76
  - 多矩阵并行支持
76
77
 
77
78
  </details>
@@ -177,7 +178,7 @@ pnpm exec expo-harmony build-hap --mode release
177
178
  <!-- GENERATED:readme-support-matrix:start -->
178
179
  - `verified`:唯一公开矩阵仍是 `expo55-rnoh082-ui-stack`
179
180
  - `preview`:`expo-file-system`, `expo-image-picker`, `expo-location`, `expo-camera`, `expo-secure-store`, `expo-asset`, `expo-device`, `expo-clipboard`, `expo-haptics`
180
- - `experimental`:`expo-notifications`, `react-native-gesture-handler`, `@react-native-async-storage/async-storage`, `react-native-screens`, `react-native-safe-area-context`
181
+ - `experimental`:`expo-notifications`, `react-native-gesture-handler`, `@react-native-async-storage/async-storage`, `react-native-screens`, `react-native-safe-area-context`, `react-native-webview`, `jpush-react-native`, `expo-media-library`, `lottie-react-native`, `@shopify/react-native-skia`
181
182
 
182
183
  `doctor --strict` 继续只代表 `verified`。`doctor --target-tier preview` 会在同一 runtime matrix 下额外放行 preview 能力,但这不等于它们已经进入正式承诺。
183
184
 
@@ -301,6 +301,10 @@ async function ensureHarmonyBuildProfileSupportsNormalizedLocalDeps(harmonyProje
301
301
  moduleEntry?.name === localHarPackage.moduleName);
302
302
  });
303
303
  if (existingModule) {
304
+ if (existingModule.name !== localHarPackage.moduleName) {
305
+ existingModule.name = localHarPackage.moduleName;
306
+ didChange = true;
307
+ }
304
308
  if (existingModule.srcPath !== relativeDirectory) {
305
309
  existingModule.srcPath = relativeDirectory;
306
310
  didChange = true;
@@ -365,9 +365,7 @@ async function buildHapProject(projectRoot, options) {
365
365
  await (0, localHar_1.patchRnohGeneratedCodegenForNormalizedLocalPackage)(harmonyProjectRoot);
366
366
  }
367
367
  await (0, localHar_1.patchKnownHarmonyAdapterCodegenOutputs)(harmonyProjectRoot);
368
- if (options.mode === 'release') {
369
- restoreLocalSigningBuildProfile = await temporarilyMergeLocalSigningIntoBuildProfile(loadedProject.projectRoot, harmonyProjectRoot);
370
- }
368
+ restoreLocalSigningBuildProfile = await temporarilyMergeLocalSigningIntoBuildProfile(loadedProject.projectRoot, harmonyProjectRoot);
371
369
  const hvigorCommand = (0, commands_1.buildInvocation)(envReport.hvigorPath, [
372
370
  'assembleHap',
373
371
  '--no-daemon',
@@ -1,6 +1,6 @@
1
1
  export declare const TOOLKIT_PACKAGE_NAME = "expo-harmony-toolkit";
2
2
  export declare const CLI_NAME = "expo-harmony";
3
- export declare const TOOLKIT_VERSION = "1.9.2";
3
+ export declare const TOOLKIT_VERSION = "1.10.0";
4
4
  export declare const TEMPLATE_VERSION = "rnoh-0.82.29";
5
5
  export declare const RNOH_VERSION = "0.82.29";
6
6
  export declare const RNOH_CLI_VERSION = "0.82.29";
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DESIRED_PACKAGE_SCRIPTS = exports.HARMONY_RUNTIME_PRELUDE_RELATIVE_PATH = exports.HARMONY_ROUTER_ENTRY_FILENAME = exports.STRICT_ENV_EXIT_CODE = exports.STRICT_DOCTOR_EXIT_CODE = exports.DEFAULT_HVIGOR_PLUGIN_FILENAME = exports.PREBUILD_METADATA_FILENAME = exports.TOOLKIT_CONFIG_FILENAME = exports.BUILD_REPORT_FILENAME = exports.ENV_REPORT_FILENAME = exports.DOCTOR_REPORT_FILENAME = exports.MANIFEST_FILENAME = exports.SIGNING_LOCAL_EXAMPLE_FILENAME = exports.SIGNING_LOCAL_FILENAME = exports.GENERATED_SHIMS_DIR = exports.GENERATED_DIR = exports.SUPPORTED_EXPO_SDKS = exports.RNOH_CLI_VERSION = exports.RNOH_VERSION = exports.TEMPLATE_VERSION = exports.TOOLKIT_VERSION = exports.CLI_NAME = exports.TOOLKIT_PACKAGE_NAME = void 0;
4
4
  exports.TOOLKIT_PACKAGE_NAME = 'expo-harmony-toolkit';
5
5
  exports.CLI_NAME = 'expo-harmony';
6
- exports.TOOLKIT_VERSION = '1.9.2';
6
+ exports.TOOLKIT_VERSION = '1.10.0';
7
7
  exports.TEMPLATE_VERSION = 'rnoh-0.82.29';
8
8
  exports.RNOH_VERSION = '0.82.29';
9
9
  exports.RNOH_CLI_VERSION = '0.82.29';
@@ -30,6 +30,10 @@ const FORMAL_EXPERIMENTAL_ADAPTER_PAIRS = [
30
30
  canonicalPackageName: '@react-native-async-storage/async-storage',
31
31
  adapterPackageName: '@react-native-oh-tpl/async-storage',
32
32
  },
33
+ {
34
+ canonicalPackageName: 'react-native-webview',
35
+ adapterPackageName: '@react-native-oh-tpl/react-native-webview',
36
+ },
33
37
  {
34
38
  canonicalPackageName: 'react-native-screens',
35
39
  adapterPackageName: '@react-native-oh-tpl/react-native-screens',
@@ -38,6 +42,18 @@ const FORMAL_EXPERIMENTAL_ADAPTER_PAIRS = [
38
42
  canonicalPackageName: 'react-native-gesture-handler',
39
43
  adapterPackageName: '@react-native-oh-tpl/react-native-gesture-handler',
40
44
  },
45
+ {
46
+ canonicalPackageName: 'lottie-react-native',
47
+ adapterPackageName: '@react-native-oh-tpl/lottie-react-native',
48
+ },
49
+ {
50
+ canonicalPackageName: 'expo-media-library',
51
+ adapterPackageName: '@react-native-oh-tpl/camera-roll',
52
+ },
53
+ {
54
+ canonicalPackageName: '@shopify/react-native-skia',
55
+ adapterPackageName: '@react-native-oh-tpl/react-native-skia',
56
+ },
41
57
  ];
42
58
  const THIRD_PARTY_WAVE_A_PACKAGE_NAMES = new Set([
43
59
  '@react-native-async-storage/async-storage',
@@ -46,6 +62,20 @@ const THIRD_PARTY_WAVE_A_PACKAGE_NAMES = new Set([
46
62
  '@react-native-oh-tpl/react-native-screens',
47
63
  'react-native-safe-area-context',
48
64
  ]);
65
+ const THIRD_PARTY_WAVE_B_PACKAGE_NAMES = new Set([
66
+ 'react-native-webview',
67
+ '@react-native-oh-tpl/react-native-webview',
68
+ 'jpush-react-native',
69
+ 'jcore-react-native',
70
+ 'mx-jpush-expo',
71
+ 'expo-notifications',
72
+ 'expo-media-library',
73
+ '@react-native-oh-tpl/camera-roll',
74
+ 'lottie-react-native',
75
+ '@react-native-oh-tpl/lottie-react-native',
76
+ '@shopify/react-native-skia',
77
+ '@react-native-oh-tpl/react-native-skia',
78
+ ]);
49
79
  async function buildDoctorReport(projectRoot, options = {}) {
50
80
  const loadedProject = await (0, project_1.loadProject)(projectRoot);
51
81
  const doctorConfig = (0, project_1.resolveExpoHarmonyDoctorConfig)(loadedProject.expoConfig);
@@ -469,47 +499,44 @@ function buildNextActions(input) {
469
499
  'config.scheme.missing',
470
500
  'config.bundle_script.mismatch',
471
501
  ].includes(issue.code));
502
+ const hasThirdPartyWaveA = dependencies.some((dependency) => THIRD_PARTY_WAVE_A_PACKAGE_NAMES.has(dependency.name));
503
+ const hasThirdPartyWaveB = dependencies.some((dependency) => THIRD_PARTY_WAVE_B_PACKAGE_NAMES.has(dependency.name));
472
504
  if (hasBlockingIssueCode(blockingIssues, 'matrix.expo_sdk.unsupported') ||
473
505
  hasBlockingIssueCode(blockingIssues, 'dependency.version_mismatch') ||
474
506
  hasBlockingIssueCode(blockingIssues, 'dependency.specifier_mismatch') ||
475
507
  hasBlockingIssueCode(blockingIssues, 'dependency.required_missing')) {
476
508
  actions.push(`Align Expo SDK, React Native, RNOH, and validated adapter versions to ${validatedMatrices_1.DEFAULT_VALIDATED_MATRIX_ID}, then rerun \`expo-harmony doctor --project-root . --strict\`.`);
477
509
  }
510
+ if (coverageProfile === 'bare') {
511
+ actions.push('Keep this project on the bare workflow track for now: preserve the native directories, use `expo-harmony doctor --project-root .` for classification, and only claim verified support after bare workflow support lands in the mainline capability catalog.');
512
+ }
513
+ if (hasRouterBlockingIssues) {
514
+ actions.push('Add the missing expo-router peers/plugin/scheme or update the Harmony bundle script to use `expo-harmony bundle`, then rerun doctor before trusting router builds.');
515
+ }
516
+ if (hasBlockingIssueCode(blockingIssues, 'config.native_identifier.missing')) {
517
+ actions.push('Set `android.package` or `ios.bundleIdentifier` in Expo config before expecting a strict Harmony build path.');
518
+ }
478
519
  if (targetTier === 'verified' && hasPreviewCapabilities) {
479
520
  actions.push('Use `expo-harmony doctor --project-root . --target-tier preview` to measure the current preview-capability baseline while keeping `latest` pinned to verified-only releases.');
480
521
  }
481
522
  if (hasPreviewCapabilities) {
482
523
  actions.push('Keep combined sample smoke for regression coverage, but track bundle/debug/device/release evidence separately for each preview capability before promotion.');
483
524
  }
484
- switch (coverageProfile) {
485
- case 'managed-core':
486
- actions.push('Stay on the verified lane: rerun `expo-harmony sync-template --project-root .`, `expo-harmony bundle --project-root .`, and `expo-harmony build-hap --project-root . --mode debug` before claiming release readiness.');
487
- break;
488
- case 'managed-native-heavy':
489
- actions.push('After every native-capability change, rerun `expo-harmony sync-template --project-root .`, `expo-harmony bundle --project-root .`, and `expo-harmony build-hap --project-root . --mode debug` to keep the managed sidecar and preview evidence aligned.');
490
- break;
491
- case 'bare':
492
- actions.push('Keep this project on the bare workflow track for now: preserve the native directories, use `expo-harmony doctor --project-root .` for classification, and only claim verified support after bare workflow support lands in the mainline capability catalog.');
493
- break;
494
- case 'third-party-native-heavy':
495
- if (dependencies.some((dependency) => THIRD_PARTY_WAVE_A_PACKAGE_NAMES.has(dependency.name))) {
496
- actions.push('Keep Third-party Native Wave A on `doctor --target-tier experimental`: pair async-storage and screens with their Harmony adapters, keep safe-area on the toolkit shim, and close device/release evidence before any promotion.');
497
- }
498
- else {
499
- actions.push('Isolate third-party native packages and onboard them through the mainline capability catalog one by one; start with `react-native-gesture-handler` if it is present, and treat unknown native surfaces as explicit unblockers rather than matrix drift.');
500
- }
501
- break;
502
- }
503
- if (hasRouterBlockingIssues) {
504
- actions.push('Add the missing expo-router peers/plugin/scheme or update the Harmony bundle script to use `expo-harmony bundle`, then rerun doctor before trusting router builds.');
505
- }
506
525
  if (blockingIssues.some((issue) => issue.code === 'dependency.not_allowed' &&
507
526
  (issue.subject === 'react-native-gesture-handler' ||
508
527
  issue.subject === '@react-native-oh-tpl/react-native-gesture-handler'))) {
509
528
  actions.push('Keep `react-native-gesture-handler` on the formal experimental slice until its Harmony adapter path closes device and release evidence.');
510
529
  }
511
- if (hasBlockingIssueCode(blockingIssues, 'config.native_identifier.missing')) {
512
- actions.push('Set `android.package` or `ios.bundleIdentifier` in Expo config before expecting a strict Harmony build path.');
530
+ if (coverageProfile === 'third-party-native-heavy') {
531
+ if (hasThirdPartyWaveA) {
532
+ actions.push('Keep Third-party Native Wave A on `doctor --target-tier experimental`: pair async-storage and screens with their Harmony adapters, keep safe-area on the toolkit shim, and close device/release evidence before any promotion.');
533
+ }
534
+ if (hasThirdPartyWaveB) {
535
+ actions.push('Keep Third-party Native Wave B on `doctor --target-tier experimental`: pair ccnubox WebView, media-library, Lottie, and Skia surfaces with their Harmony adapters, keep JPush runtime evidence separate, and require debug/release simulator delivery gates before shipping.');
536
+ }
537
+ if (!hasThirdPartyWaveA && !hasThirdPartyWaveB) {
538
+ actions.push('Isolate third-party native packages and onboard them through the mainline capability catalog one by one; start with `react-native-gesture-handler` if it is present, and treat unknown native surfaces as explicit unblockers rather than matrix drift.');
539
+ }
513
540
  }
514
541
  if (dependencies.some((dependency) => dependency.buildabilityRisk === 'native-risk')) {
515
542
  actions.push('Inspect unknown native-looking dependencies and either replace them, gate them behind preview work, or onboard them explicitly before promising Harmony portability.');
@@ -517,6 +544,12 @@ function buildNextActions(input) {
517
544
  if (dependencies.some((dependency) => dependency.buildabilityRisk === 'js-only-unknown')) {
518
545
  actions.push('Unknown JavaScript-only packages still sit outside the public matrix; verify bundling manually, but prioritize native gaps first.');
519
546
  }
547
+ if (coverageProfile === 'managed-core') {
548
+ actions.push('Stay on the verified lane: rerun `expo-harmony sync-template --project-root .`, `expo-harmony bundle --project-root .`, and `expo-harmony build-hap --project-root . --mode debug` before claiming release readiness.');
549
+ }
550
+ if (coverageProfile === 'managed-native-heavy') {
551
+ actions.push('After every native-capability change, rerun `expo-harmony sync-template --project-root .`, `expo-harmony bundle --project-root .`, and `expo-harmony build-hap --project-root . --mode debug` to keep the managed sidecar and preview evidence aligned.');
552
+ }
520
553
  return dedupeStrings(actions);
521
554
  }
522
555
  function hasBlockingIssueCode(issues, code) {
@@ -18,37 +18,37 @@ const PREVIEW_BASELINE_EVIDENCE_SOURCE = {
18
18
  device: 'manual-doc',
19
19
  release: 'none',
20
20
  };
21
- const EXPLORATORY_EVIDENCE = {
22
- bundle: false,
23
- debugBuild: false,
21
+ const APP_FOUNDATION_BASELINE_EVIDENCE = {
22
+ bundle: true,
23
+ debugBuild: true,
24
24
  device: false,
25
25
  release: false,
26
26
  };
27
- const EXPLORATORY_EVIDENCE_SOURCE = {
28
- bundle: 'none',
29
- debugBuild: 'none',
27
+ const APP_FOUNDATION_BASELINE_EVIDENCE_SOURCE = {
28
+ bundle: 'automated',
29
+ debugBuild: 'automated',
30
30
  device: 'none',
31
31
  release: 'none',
32
32
  };
33
- const APP_FOUNDATION_BASELINE_EVIDENCE = {
33
+ const THIRD_PARTY_WAVE_A_BASELINE_EVIDENCE = {
34
34
  bundle: true,
35
35
  debugBuild: true,
36
36
  device: false,
37
37
  release: false,
38
38
  };
39
- const APP_FOUNDATION_BASELINE_EVIDENCE_SOURCE = {
39
+ const THIRD_PARTY_WAVE_A_BASELINE_EVIDENCE_SOURCE = {
40
40
  bundle: 'automated',
41
41
  debugBuild: 'automated',
42
42
  device: 'none',
43
43
  release: 'none',
44
44
  };
45
- const THIRD_PARTY_WAVE_A_BASELINE_EVIDENCE = {
45
+ const THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE = {
46
46
  bundle: true,
47
47
  debugBuild: true,
48
48
  device: false,
49
49
  release: false,
50
50
  };
51
- const THIRD_PARTY_WAVE_A_BASELINE_EVIDENCE_SOURCE = {
51
+ const THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE = {
52
52
  bundle: 'automated',
53
53
  debugBuild: 'automated',
54
54
  device: 'none',
@@ -241,17 +241,17 @@ exports.CAPABILITY_DEFINITIONS = [
241
241
  status: 'manual',
242
242
  supportTier: 'experimental',
243
243
  runtimeMode: 'shim',
244
- evidence: EXPLORATORY_EVIDENCE,
245
- evidenceSource: EXPLORATORY_EVIDENCE_SOURCE,
246
- note: 'Notifications stay below the public promise until a complete Harmony delivery story is validated end to end.',
244
+ evidence: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE,
245
+ evidenceSource: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE,
246
+ note: 'v1.9.3 Wave B keeps Expo Notifications on a safe experimental shim for ccnubox push flows while JPush delivery and signed-runtime behavior remain separate evidence gates.',
247
247
  docsUrl: 'https://github.com/react-native-oh-library',
248
248
  nativePackageNames: [],
249
249
  harmonyPermissions: ['ohos.permission.NOTIFICATION_CONTROLLER'],
250
- sampleRoute: '/notifications',
250
+ sampleRoute: '/third-party-wave-b/notifications',
251
251
  acceptanceChecklist: [
252
- 'Register for notifications on a signed build.',
253
- 'Receive a foreground notification.',
254
- 'Validate open-from-notification lifecycle.',
252
+ 'Bundle notification permission and channel setup paths without crashing.',
253
+ 'Keep foreground receipt, click, and cold-start delivery pending signed simulator and device evidence.',
254
+ 'Do not treat simulator app-shell launch as notification delivery acceptance.',
255
255
  ],
256
256
  },
257
257
  {
@@ -330,6 +330,101 @@ exports.CAPABILITY_DEFINITIONS = [
330
330
  'Validate real native inset measurement separately before any adapter promotion.',
331
331
  ],
332
332
  },
333
+ {
334
+ id: 'react-native-webview',
335
+ packageName: 'react-native-webview',
336
+ status: 'manual',
337
+ supportTier: 'experimental',
338
+ runtimeMode: 'adapter',
339
+ evidence: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE,
340
+ evidenceSource: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE,
341
+ note: 'v1.9.3 Wave B tracks ccnubox WebView surfaces through the Harmony adapter, but navigation, injected scripts, and release runtime stability remain promotion evidence.',
342
+ docsUrl: 'https://github.com/react-native-oh-library/usage-docs/blob/master/en/react-native-webview.md',
343
+ nativePackageNames: ['@react-native-oh-tpl/react-native-webview'],
344
+ harmonyPermissions: [],
345
+ sampleRoute: '/third-party-wave-b/webview',
346
+ acceptanceChecklist: [
347
+ 'Install react-native-webview with the matching Harmony adapter.',
348
+ 'Bundle a minimal WebView surface with message passing and navigation callbacks.',
349
+ 'Validate signed simulator startup and real WebView runtime behavior before any promotion.',
350
+ ],
351
+ },
352
+ {
353
+ id: 'jpush-react-native',
354
+ packageName: 'jpush-react-native',
355
+ status: 'manual',
356
+ supportTier: 'experimental',
357
+ runtimeMode: 'adapter',
358
+ evidence: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE,
359
+ evidenceSource: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE,
360
+ note: 'v1.9.3 Wave B keeps ccnubox JPush runtime dependencies in formal telemetry; registrationId, arrival, click, and cold-start payloads still require signed runtime evidence.',
361
+ docsUrl: 'https://docs.jiguang.cn/jpush/client/HarmonyOS/hmos_guide',
362
+ nativePackageNames: ['jcore-react-native'],
363
+ harmonyPermissions: ['ohos.permission.NOTIFICATION_CONTROLLER'],
364
+ sampleRoute: '/third-party-wave-b/jpush',
365
+ acceptanceChecklist: [
366
+ 'Keep jpush-react-native, jcore-react-native, and mx-jpush-expo visible in doctor reports.',
367
+ 'Bundle guarded JPush init and registrationId lookup paths without native-module crashes.',
368
+ 'Record signed simulator and device push delivery evidence before any promotion.',
369
+ ],
370
+ },
371
+ {
372
+ id: 'expo-media-library',
373
+ packageName: 'expo-media-library',
374
+ status: 'manual',
375
+ supportTier: 'experimental',
376
+ runtimeMode: 'adapter',
377
+ evidence: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE,
378
+ evidenceSource: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE,
379
+ note: 'v1.9.3 Wave B tracks ccnubox media-library save flows through the camera-roll Harmony adapter while gallery write/read behavior remains runtime evidence.',
380
+ docsUrl: 'https://github.com/react-native-oh-library',
381
+ nativePackageNames: ['@react-native-oh-tpl/camera-roll'],
382
+ harmonyPermissions: ['ohos.permission.READ_IMAGEVIDEO', 'ohos.permission.WRITE_IMAGEVIDEO'],
383
+ sampleRoute: '/third-party-wave-b/media-library',
384
+ acceptanceChecklist: [
385
+ 'Install expo-media-library with the camera-roll Harmony adapter available.',
386
+ 'Bundle permission and create-asset code paths used by ccnubox screenshots.',
387
+ 'Validate gallery write/read behavior on signed simulator and device before promotion.',
388
+ ],
389
+ },
390
+ {
391
+ id: 'lottie-react-native',
392
+ packageName: 'lottie-react-native',
393
+ status: 'manual',
394
+ supportTier: 'experimental',
395
+ runtimeMode: 'adapter',
396
+ evidence: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE,
397
+ evidenceSource: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE,
398
+ note: 'v1.9.3 Wave B tracks ccnubox Lottie animation surfaces through the Harmony adapter, but animation playback remains simulator and device smoke evidence.',
399
+ docsUrl: 'https://github.com/react-native-oh-library',
400
+ nativePackageNames: ['@react-native-oh-tpl/lottie-react-native'],
401
+ harmonyPermissions: [],
402
+ sampleRoute: '/third-party-wave-b/lottie',
403
+ acceptanceChecklist: [
404
+ 'Install lottie-react-native with the matching Harmony adapter.',
405
+ 'Bundle a minimal LottieView surface and local animation asset path.',
406
+ 'Validate playback on signed simulator and device before promotion.',
407
+ ],
408
+ },
409
+ {
410
+ id: 'react-native-skia',
411
+ packageName: '@shopify/react-native-skia',
412
+ status: 'manual',
413
+ supportTier: 'experimental',
414
+ runtimeMode: 'adapter',
415
+ evidence: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE,
416
+ evidenceSource: THIRD_PARTY_WAVE_B_BASELINE_EVIDENCE_SOURCE,
417
+ note: 'v1.9.3 Wave B tracks ccnubox Skia timetable rendering through the Harmony adapter direction while canvas rendering remains runtime evidence.',
418
+ docsUrl: 'https://github.com/react-native-oh-library',
419
+ nativePackageNames: ['@react-native-oh-tpl/react-native-skia'],
420
+ harmonyPermissions: [],
421
+ sampleRoute: '/third-party-wave-b/skia',
422
+ acceptanceChecklist: [
423
+ 'Install @shopify/react-native-skia with the Harmony Skia adapter available.',
424
+ 'Bundle a minimal Canvas/Skia import surface used by timetable rendering.',
425
+ 'Validate actual canvas rendering on signed simulator and device before promotion.',
426
+ ],
427
+ },
333
428
  ];
334
429
  exports.CAPABILITY_BY_PACKAGE = Object.fromEntries(exports.CAPABILITY_DEFINITIONS.map((definition) => [definition.packageName, definition]));
335
430
  const SUPPORT_TIER_ORDER = {
@@ -156,7 +156,7 @@ exports.DEPENDENCY_CATALOG = {
156
156
  'react-native-webview': {
157
157
  status: 'manual',
158
158
  supportTier: 'experimental',
159
- note: 'WebView is a common app-shell blocker. Treat it as an experimental intake dependency until the Harmony runtime path is validated on device.',
159
+ note: 'v1.9.3 Wave B tracks ccnubox WebView usage through the Harmony adapter, but navigation, injected scripts, and release runtime behavior remain experimental evidence.',
160
160
  docsUrl: 'https://github.com/react-native-oh-library',
161
161
  },
162
162
  ...UI_STACK_COMPATIBILITY_RECORDS,
@@ -289,7 +289,7 @@ exports.DEPENDENCY_CATALOG = {
289
289
  'expo-media-library': {
290
290
  status: 'manual',
291
291
  supportTier: 'experimental',
292
- note: 'Media-library write/read flows should be backed by the Harmony camera-roll adapter for screenshot save acceptance.',
292
+ note: 'v1.9.3 Wave B tracks media-library screenshot save flows through the Harmony camera-roll adapter; gallery write/read behavior still needs signed runtime evidence.',
293
293
  replacement: '@react-native-oh-tpl/camera-roll',
294
294
  },
295
295
  'expo-secure-store': {
@@ -325,19 +325,19 @@ exports.DEPENDENCY_CATALOG = {
325
325
  'jcore-react-native': {
326
326
  status: 'manual',
327
327
  supportTier: 'experimental',
328
- note: 'JCore is accepted as part of the JPush Harmony intake path, but device-side SDK evidence is required.',
328
+ note: 'v1.9.3 Wave B keeps JCore visible as the JPush runtime foundation, but SDK registration and delivery still need signed runtime evidence.',
329
329
  docsUrl: 'https://docs.jiguang.cn/jpush/client/HarmonyOS/hmos_guide',
330
330
  },
331
331
  'jpush-react-native': {
332
332
  status: 'manual',
333
333
  supportTier: 'experimental',
334
- note: 'JPush is a real runtime requirement for ccnubox. Keep it in the catalog and require a Harmony SDK bridge plus device evidence for registrationId, arrival, click, and cold-start payloads.',
334
+ note: 'v1.9.3 Wave B keeps JPush in formal telemetry for ccnubox; registrationId, arrival, click, and cold-start payloads require signed runtime evidence.',
335
335
  docsUrl: 'https://docs.jiguang.cn/jpush/client/HarmonyOS/hmos_guide',
336
336
  },
337
337
  'mx-jpush-expo': {
338
338
  status: 'manual',
339
339
  supportTier: 'experimental',
340
- note: 'The Expo config plugin may be excluded from Harmony config processing, but the JPush runtime dependency must stay visible in doctor reports.',
340
+ note: 'v1.9.3 Wave B treats this config plugin as JPush intake metadata; it may be excluded from config processing while runtime JPush dependencies stay visible in doctor reports.',
341
341
  docsUrl: 'https://docs.jiguang.cn/jpush/client/HarmonyOS/hmos_guide',
342
342
  },
343
343
  'react-native-draggable-grid': {
@@ -8,4 +8,4 @@ export declare const SUPPORTING_SAMPLE_PATHS: readonly ["examples/official-app-s
8
8
  export declare const VERIFIED_JS_UI_CAPABILITY_NAMES: readonly ["expo-router", "expo-linking", "expo-constants", ...("react-native-reanimated" | "react-native-svg")[]];
9
9
  export declare const PREVIEW_CAPABILITY_DEFINITIONS: import("..").CapabilityDefinition[];
10
10
  export declare const EXPERIMENTAL_CAPABILITY_NAMES: readonly string[];
11
- export declare const PUBLIC_CURRENT_VERSION = "1.9.2";
11
+ export declare const PUBLIC_CURRENT_VERSION = "1.10.0";
@@ -5,5 +5,6 @@ export declare function renderSupportMatrixVerifiedMatrix(locale: DocsLocale): s
5
5
  export declare function renderSupportMatrixVerifiedAllowlist(): string;
6
6
  export declare function renderSupportMatrixCapabilityTelemetry(locale: DocsLocale): string;
7
7
  export declare function renderSupportMatrixPreviewCapabilities(locale: DocsLocale): string;
8
+ export declare function renderSupportMatrixExperimentalCapabilities(locale: DocsLocale): string;
8
9
  export declare function renderSupportMatrixUiStackRules(locale: DocsLocale): string;
9
10
  export declare function renderSupportMatrixReleaseTracks(locale: DocsLocale): string;
@@ -6,9 +6,11 @@ exports.renderSupportMatrixVerifiedMatrix = renderSupportMatrixVerifiedMatrix;
6
6
  exports.renderSupportMatrixVerifiedAllowlist = renderSupportMatrixVerifiedAllowlist;
7
7
  exports.renderSupportMatrixCapabilityTelemetry = renderSupportMatrixCapabilityTelemetry;
8
8
  exports.renderSupportMatrixPreviewCapabilities = renderSupportMatrixPreviewCapabilities;
9
+ exports.renderSupportMatrixExperimentalCapabilities = renderSupportMatrixExperimentalCapabilities;
9
10
  exports.renderSupportMatrixUiStackRules = renderSupportMatrixUiStackRules;
10
11
  exports.renderSupportMatrixReleaseTracks = renderSupportMatrixReleaseTracks;
11
12
  const publicDocs_1 = require("../data/publicDocs");
13
+ const capabilities_1 = require("../data/capabilities");
12
14
  const validatedMatrices_1 = require("../data/validatedMatrices");
13
15
  const uiStack_1 = require("../data/uiStack");
14
16
  const matrix = validatedMatrices_1.VALIDATED_RELEASE_MATRICES[validatedMatrices_1.DEFAULT_VALIDATED_MATRIX_ID];
@@ -33,8 +35,8 @@ function renderReadmeCurrentStatus(locale) {
33
35
  ? `\`latest\` = ${publicDocs_1.PUBLIC_RELEASE_TRACKS.latest};\`next\` = ${publicDocs_1.PUBLIC_RELEASE_TRACKS.next}`
34
36
  : `\`latest\` = fully accepted \`verified\` only; \`next\` = ${publicDocs_1.PUBLIC_RELEASE_TRACKS.next}`;
35
37
  const inputValue = locale === 'zh'
36
- ? 'Managed/CNG Expo 项目;bare workflow intake baseline'
37
- : 'Managed/CNG Expo projects; bare workflow intake baseline';
38
+ ? 'Managed/CNG Expo 项目;bare catalog 外项目 intake 分类'
39
+ : 'Managed/CNG Expo projects; bare and catalog-out intake classification';
38
40
  const listJoiner = locale === 'zh' ? '、' : ', ';
39
41
  return [
40
42
  `| ${headers[0]} | ${headers[1]} |`,
@@ -183,6 +185,23 @@ function renderSupportMatrixPreviewCapabilities(locale) {
183
185
  }).map((row) => `| ${row} |`),
184
186
  ].join('\n');
185
187
  }
188
+ function renderSupportMatrixExperimentalCapabilities(locale) {
189
+ const headers = locale === 'zh'
190
+ ? ['Expo 能力 / 依赖', '当前层级', 'runtimeMode', 'evidence', '说明']
191
+ : ['Expo capability / dependency', 'Support tier', 'runtimeMode', 'evidence', 'Notes'];
192
+ const experimentalCapabilities = capabilities_1.CAPABILITY_DEFINITIONS.filter((definition) => definition.supportTier === 'experimental');
193
+ return [
194
+ `| ${headers.join(' | ')} |`,
195
+ `| ${headers.map(() => '---').join(' | ')} |`,
196
+ ...experimentalCapabilities.map((definition) => [
197
+ `\`${definition.packageName}\``,
198
+ `\`${definition.supportTier}\``,
199
+ `\`${definition.runtimeMode}\``,
200
+ `\`${renderEvidence(definition)}\``,
201
+ renderExperimentalCapabilityNote(definition, locale),
202
+ ].join(' | ')).map((row) => `| ${row} |`),
203
+ ].join('\n');
204
+ }
186
205
  function renderSupportMatrixUiStackRules(locale) {
187
206
  const intro = locale === 'zh'
188
207
  ? 'canonical 包与 Harmony adapter 包固定为双向强制:'
@@ -250,3 +269,12 @@ function renderEvidence(definition) {
250
269
  `release=${definition.evidence.release ? 'yes' : 'no'}[${definition.evidenceSource.release}]`,
251
270
  ].join(', ');
252
271
  }
272
+ function renderExperimentalCapabilityNote(definition, locale) {
273
+ const dependencyDirection = definition.nativePackageNames.length > 0
274
+ ? definition.nativePackageNames.join(', ')
275
+ : 'toolkit-managed bridge';
276
+ if (locale === 'en') {
277
+ return `${definition.note} Direction: ${dependencyDirection}.`;
278
+ }
279
+ return `${definition.note} 依赖方向:${dependencyDirection}。`;
280
+ }
package/docs/cli-build.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CLI 构建指南
2
2
 
3
- `v1.9.2` 延续 `verified + preview + experimental` 支持分层,把 Third-party Native Wave A 纳入 formal experimental onboarding;`expo55-rnoh082-ui-stack` 仍是唯一 verified 矩阵。
3
+ `v1.10.0` 延续 `verified + preview + experimental` 支持分层,并冻结 Any-project Intake:`doctor` 必须能分类任意 Expo 项目、标出 blocker 类型并给出有序下一步;`expo55-rnoh082-ui-stack` 仍是唯一 verified 矩阵。
4
4
 
5
5
  CLI 命令集合不变:
6
6
 
@@ -51,6 +51,11 @@ expo-harmony build-hap --mode debug
51
51
  - `@react-native-async-storage/async-storage`
52
52
  - `react-native-screens`
53
53
  - `react-native-safe-area-context`
54
+ - `react-native-webview`
55
+ - `jpush-react-native`
56
+ - `expo-media-library`
57
+ - `lottie-react-native`
58
+ - `@shopify/react-native-skia`
54
59
 
55
60
  ## UI stack 依赖安装注意事项
56
61
 
@@ -93,7 +98,7 @@ pnpm install --ignore-scripts
93
98
 
94
99
  额外说明:
95
100
 
96
- - `react-native-gesture-handler` 与 Wave A 第三方 native packages 已进入 formal experimental onboarding,但仍不属于 verified 公开承诺
101
+ - `react-native-gesture-handler` 与 Wave A / Wave B 第三方 native packages 已进入 formal experimental onboarding,但仍不属于 verified 公开承诺
97
102
  - bare workflow 当前只有 intake / debug baseline,不代表 release-ready
98
103
  - `doctor --strict` 仍只代表完整验收的 verified 能力
99
104
 
@@ -45,7 +45,7 @@ pnpm run harmony:build:release
45
45
 
46
46
  - `.expo-harmony/signing.local.example.json` 是可直接复制的本地 signing 範本
47
47
  - `.expo-harmony/signing.local.json` 是本地 signing 入口
48
- - toolkit 只会把非密钥 signing 引用写进 `harmony/build-profile.json5`;`storePassword` 与 `keyPassword` 会留在本地 signing 文件,并在 release build 期间临时注入
48
+ - toolkit 只会把非密钥 signing 引用写进 `harmony/build-profile.json5`;`storePassword` 与 `keyPassword` 会留在本地 signing 文件,并在 Hvigor build 期间临时注入后恢复
49
49
  - 如果 signing 没配置,`harmony:env` 会明确报缺失;这属于预期阻断
50
50
 
51
51
  ## 不覆盖的内容
@@ -182,7 +182,7 @@ pnpm run harmony:build:release
182
182
 
183
183
  - `.expo-harmony/signing.local.example.json` 是可直接复制的本地 signing 範本
184
184
  - `.expo-harmony/signing.local.json` 是本地 signing 入口
185
- - toolkit 只会把非密钥 signing 引用写进 `harmony/build-profile.json5`;`storePassword` 与 `keyPassword` 会留在本地 signing 文件,并在 release build 期间临时注入
185
+ - toolkit 只会把非密钥 signing 引用写进 `harmony/build-profile.json5`;`storePassword` 与 `keyPassword` 会留在本地 signing 文件,并在 Hvigor build 期间临时注入后恢复
186
186
  - 即使 release 构建可走通,在没有真机前,这四项能力也仍保持 `preview`
187
187
 
188
188
  ## 当前结论
package/docs/roadmap.md CHANGED
@@ -66,7 +66,7 @@
66
66
 
67
67
  ## 当前主线
68
68
 
69
- `v1.8.x` 已完成 repo 内可收口项,当前主线切到 `v1.9.x`。`v1.9.0` 先落 bare workflow baseline、app foundation modules 与 `react-native-gesture-handler` formal slice;`v1.9.1` 作为 build-hap patch release,补上 HAR normalize opt-out;`v1.9.2` 推进 Third-party Native Wave A,把 async-storage、screens 与 safe-area 拉进 formal experimental onboarding。剩余需要真机或 release HAP 的证据继续保留在 v1.8.x capability board,不阻塞 v1.9.x 的 bare / foundation / third-party onboarding 工作。
69
+ `v1.8.x` 已完成 repo 内可收口项,当前主线切到 `v1.9.x`。`v1.9.0` 先落 bare workflow baseline、app foundation modules 与 `react-native-gesture-handler` formal slice;`v1.9.1` 作为 build-hap patch release,补上 HAR normalize opt-out;`v1.9.2` 推进 Third-party Native Wave A,把 async-storage、screens 与 safe-area 拉进 formal experimental onboarding;`v1.9.3` 推进 ccnubox-first Third-party Native Wave B 与 regression farm。剩余需要真机或 release HAP 的证据继续保留在 v1.8.x capability board,不阻塞 v1.9.x 的 bare / foundation / third-party onboarding 工作。
70
70
 
71
71
  ### v1.8.0 Intake Hardening + Parallel Promotion
72
72
 
@@ -204,21 +204,33 @@
204
204
 
205
205
  目标日期:`2026-10-31`
206
206
 
207
+ 状态:implementation baseline complete;simulator delivery gate complete on ccnubox_rn;device / release evidence carryover。
208
+
207
209
  目标:扩大第三方 native 覆盖,并把 `v1.9.0` 建好的最小 regression farm 扩容成持续回归面。
208
210
 
209
- - 第二批高频第三方 native 依赖进入主线
211
+ - 第二批高频第三方 native 依赖进入主线:
212
+ - `react-native-webview`
213
+ - JPush runtime:`jpush-react-native`、`jcore-react-native`、`mx-jpush-expo`
214
+ - `expo-notifications`
215
+ - `expo-media-library`
216
+ - `lottie-react-native`
217
+ - `@shopify/react-native-skia`
210
218
  - 扩容 project-shape regression farm:
211
219
  - managed core
212
220
  - managed native heavy
213
221
  - bare
214
222
  - third-party native heavy
215
223
  - 至少维护一组“未知项目导入 -> doctor 分类 -> nextActions -> sample/build gate”的持续回归案例
224
+ - ccnubox-first Wave B 以 `experimental` + formal adapter/shim slice 记录,不改变 `verified` 边界
225
+ - debug / release HAP simulator delivery gate 必须单独记录;没有 `hdc` target 时不得把 build evidence 表述为 simulator pass
216
226
  - 继续收口 preview capability 的 release evidence,尽量减少 `v2.0.0` 前的残留灰区
217
227
 
218
228
  ### v1.10.0 Any-project Intake Freeze
219
229
 
220
230
  目标日期:`2026-11-15`
221
231
 
232
+ 状态:`implementation target`,本阶段首个正式发布版本直接使用 `1.10.0` / `v1.10.0`;发布动作另行执行。
233
+
222
234
  目标:先冻结“任何 Expo 项目”入口面的产品故事,确保不存在无法分类、无法给下一步、无法明确阻断原因的项目。
223
235
 
224
236
  - `doctor` 对任意 Expo 项目必须满足:
@@ -228,6 +240,14 @@
228
240
  - roadmap / support matrix / acceptance board 与实际 catalog 保持零漂移
229
241
  - 对外叙事从“更多项目开始进入主线”升级成“任何项目都有明确处理路径”
230
242
 
243
+ Acceptance checklist:
244
+
245
+ - 新增 `fixtures/v110-*` 覆盖 catalog managed、bare、unknown JS-only、unknown native-looking、mixed intake
246
+ - `nextActions[]` 固定按版本矩阵问题 -> 项目形态问题 -> native blocker -> unknown JS/native 依赖 -> build gate 排序
247
+ - `acceptance/v1.10.0-acceptance.md` 记录 repo-only gate 与边界
248
+ - 不提升任何 capability 到 `verified`
249
+ - 不要求真机 device evidence
250
+
231
251
  ### v1.11.0 Final Blocker Burn-down
232
252
 
233
253
  目标日期:`2026-11-30`
@@ -59,7 +59,7 @@ expo-harmony env
59
59
  - `release` 构建不应视为 ready
60
60
  - 可以直接从 `.expo-harmony/signing.local.example.json` 复制出 `.expo-harmony/signing.local.json` 再填入真实材料
61
61
 
62
- `expo-harmony init` / `sync-template` 只会把非密钥 signing 引用写入可版本化的 `harmony/build-profile.json5`。`storePassword` 与 `keyPassword` 只应保留在 `.expo-harmony/signing.local.json`;`build-hap --mode release` 会在本地构建期间临时注入这些 secret,并在 Hvigor 结束后恢复 `build-profile.json5`。
62
+ `expo-harmony init` / `sync-template` 只会把非密钥 signing 引用写入可版本化的 `harmony/build-profile.json5`。`storePassword` 与 `keyPassword` 只应保留在 `.expo-harmony/signing.local.json`;`build-hap` 会在本地 Hvigor 构建期间临时注入这些 secret,并在 Hvigor 结束后恢复 `build-profile.json5`。没有本地 signing config 的 debug 构建仍不需要 release signing。
63
63
 
64
64
  ## 推荐流程
65
65
 
@@ -1,6 +1,6 @@
1
- # v1.9 支持矩阵
1
+ # v1.10 支持矩阵
2
2
 
3
- `v1.9` 继续采用 tiered support model,并把“层级”与“晋升距离”拆开表达:
3
+ `v1.10` 继续采用 tiered support model,并把“层级”“晋升距离”与“intake 分类”拆开表达:
4
4
 
5
5
  - `supportTier` 表示公开承诺层级
6
6
  - `runtimeMode` 表示当前运行时接入形态:`shim`、`adapter`、`verified`
@@ -14,7 +14,8 @@
14
14
  - bare workflow 与第三方 native package 不再被描述成“收官后才考虑的另一条 extension 终局”
15
15
  - `v2.0.0` 本身被定义成“任何 Expo 项目都能可靠打包成鸿蒙 App”的目标版本
16
16
  - 但当前公开承诺依旧没有放宽;它们只是进入同一主线 backlog,而不是已经进入 `verified`
17
- - `v1.9.2` 新增的是 Third-party Native Wave A formal experimental onboarding,不是 verified 扩容
17
+ - `v1.10.0` 新增的是 Any-project Intake Freeze:任何 Expo 项目进入 `doctor` 后都应有分类、明确 blocker 类型与有序 `nextActions`
18
+ - 这不是 verified 扩容;`latest` 仍只承诺完整验收的 `verified` 能力,catalog 外项目只承诺可诊断路径
18
19
 
19
20
  `doctor --strict` 继续只代表 `verified`。
20
21
 
@@ -134,13 +135,20 @@
134
135
 
135
136
  ## Experimental 能力
136
137
 
138
+ <!-- GENERATED:support-matrix-experimental-capabilities:start -->
137
139
  | Expo 能力 / 依赖 | 当前层级 | runtimeMode | evidence | 说明 |
138
140
  | --- | --- | --- | --- | --- |
139
- | `expo-notifications` | `experimental` | `shim` | `bundle=no, debugBuild=no, device=no, release=no` | 服务链路与交付故事未打通 |
140
- | `react-native-gesture-handler` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.0 formal acceptance slice;必须与 `@react-native-oh-tpl/react-native-gesture-handler` 成对接入,仍不在公开 verified 矩阵内 |
141
- | `@react-native-async-storage/async-storage` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.2 Wave A formal onboarding;必须与 `@react-native-oh-tpl/async-storage` 成对接入,持久化行为仍需 device / release evidence |
142
- | `react-native-screens` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.2 Wave A formal onboarding;必须与 `@react-native-oh-tpl/react-native-screens` 成对接入,navigation-stack runtime 仍需 evidence |
143
- | `react-native-safe-area-context` | `experimental` | `shim` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.2 Wave A formal onboarding;当前仍走 toolkit-managed safe-area shim,不切换到 native adapter |
141
+ | `expo-notifications` | `experimental` | `shim` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.3 Wave B keeps Expo Notifications on a safe experimental shim for ccnubox push flows while JPush delivery and signed-runtime behavior remain separate evidence gates. 依赖方向:toolkit-managed bridge。 |
142
+ | `react-native-gesture-handler` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.0 formal acceptance slice tracks Gesture Handler through its Harmony adapter, but it remains experimental until device and release runtime evidence are closed. 依赖方向:@react-native-oh-tpl/react-native-gesture-handler |
143
+ | `@react-native-async-storage/async-storage` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.2 Wave A tracks Async Storage through its Harmony adapter, but persistence behavior remains experimental until device and release evidence are closed. 依赖方向:@react-native-oh-tpl/async-storage |
144
+ | `react-native-screens` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.2 Wave A tracks Screens through its Harmony adapter metadata, while managed autolinking and navigation-stack runtime behavior remain promotion gaps. 依赖方向:@react-native-oh-tpl/react-native-screens |
145
+ | `react-native-safe-area-context` | `experimental` | `shim` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.2 Wave A formalizes the existing toolkit safe-area shim so app-shell layouts keep bundling while native safe-area measurements stay outside verified. 依赖方向:toolkit-managed bridge。 |
146
+ | `react-native-webview` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.3 Wave B tracks ccnubox WebView surfaces through the Harmony adapter, but navigation, injected scripts, and release runtime stability remain promotion evidence. 依赖方向:@react-native-oh-tpl/react-native-webview。 |
147
+ | `jpush-react-native` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.3 Wave B keeps ccnubox JPush runtime dependencies in formal telemetry; registrationId, arrival, click, and cold-start payloads still require signed runtime evidence. 依赖方向:jcore-react-native。 |
148
+ | `expo-media-library` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.3 Wave B tracks ccnubox media-library save flows through the camera-roll Harmony adapter while gallery write/read behavior remains runtime evidence. 依赖方向:@react-native-oh-tpl/camera-roll。 |
149
+ | `lottie-react-native` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.3 Wave B tracks ccnubox Lottie animation surfaces through the Harmony adapter, but animation playback remains simulator and device smoke evidence. 依赖方向:@react-native-oh-tpl/lottie-react-native。 |
150
+ | `@shopify/react-native-skia` | `experimental` | `adapter` | `bundle=yes[automated], debugBuild=yes[automated], device=no[none], release=no[none]` | v1.9.3 Wave B tracks ccnubox Skia timetable rendering through the Harmony adapter direction while canvas rendering remains runtime evidence. 依赖方向:@react-native-oh-tpl/react-native-skia。 |
151
+ <!-- GENERATED:support-matrix-experimental-capabilities:end -->
144
152
 
145
153
  ## UI Stack 配对规则
146
154
 
@@ -201,7 +209,7 @@ expo-harmony doctor --project-root /path/to/app --target-tier preview
201
209
  - `runtimeMode !== verified`,表示即使已有部分证据,也仍不属于正式承诺
202
210
  - `coverageProfile=bare`,表示当前项目已落入 bare workflow 主线规划,但不等于当前 matrix 已正式支持 bare
203
211
  - `gapCategory=third-party-native-gap`,表示问题不应再被模糊描述成普通 matrix drift,而是主线 blocker
204
- - `nextActions[]` 的顺序即 toolkit 当前建议的处理顺序
212
+ - `nextActions[]` 的顺序即 toolkit 当前建议的处理顺序:版本矩阵问题 -> 项目形态问题 -> native blocker -> unknown JS/native 依赖 -> build gate
205
213
 
206
214
  当前公开阻断 issue code 继续包括:
207
215
 
@@ -240,7 +248,7 @@ toolkit 受管的核心产物仍包括:
240
248
 
241
249
  ## Release Tracks
242
250
 
243
- 从 `v1.8` 开始,发布节奏按双轨设计;`v1.9.0` 继续沿用同一规则:
251
+ 从 `v1.8` 开始,发布节奏按双轨设计;`v1.10.0` 继续沿用同一规则:
244
252
 
245
253
  <!-- GENERATED:support-matrix-release-tracks:start -->
246
254
  - `latest`
@@ -273,6 +281,7 @@ toolkit 受管的核心产物仍包括:
273
281
  - bare Expo;当前只进入 intake / debug baseline
274
282
  - `expo-secure-store`、`expo-asset`、`expo-device`、`expo-clipboard`、`expo-haptics` 当前仍只是 preview shim baseline
275
283
  - `@react-native-async-storage/async-storage`、`react-native-screens`、`react-native-safe-area-context` 当前仍只是 Wave A experimental onboarding
284
+ - `react-native-webview`、JPush runtime、`expo-media-library`、`lottie-react-native`、`@shopify/react-native-skia` 当前仍只是 Wave B experimental onboarding
276
285
  - 多 Expo / RNOH 并行 verified 矩阵
277
286
  - 任意第三方 native package 的即时正式承诺
278
287
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-harmony-toolkit",
3
- "version": "1.9.2",
3
+ "version": "1.10.0",
4
4
  "description": "面向 Managed/CNG Expo 项目的 HarmonyOS 迁移、准入检查与 UI-stack 构建工具链",
5
5
  "main": "app.plugin.js",
6
6
  "types": "build/index.d.ts",