@shopify/react-native-skia 2.6.4 → 2.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +7 -4
- package/android/build.gradle +22 -3
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +62 -0
- package/apple/RNSkApplePlatformContext.h +2 -0
- package/apple/RNSkApplePlatformContext.mm +71 -0
- package/apple/RNWebGPUAppleNativeBuffer.mm +33 -0
- package/cpp/api/JsiNativeBuffer.h +9 -1
- package/cpp/api/JsiSkAnimatedImageFactory.h +1 -1
- package/cpp/api/JsiSkApi.h +2 -2
- package/cpp/api/JsiSkCanvas.h +1 -1
- package/cpp/api/JsiSkDataFactory.h +1 -1
- package/cpp/api/JsiSkFont.h +1 -1
- package/cpp/api/JsiSkFontMgr.h +1 -1
- package/cpp/api/JsiSkHostObjects.h +3 -3
- package/cpp/api/JsiSkImage.h +2 -2
- package/cpp/api/JsiSkImageFactory.h +2 -2
- package/cpp/api/JsiSkPath.h +1 -1
- package/cpp/api/JsiSkPathFactory.h +1 -1
- package/cpp/api/JsiSkSurface.h +13 -5
- package/cpp/api/JsiSkTypeface.h +1 -1
- package/cpp/api/JsiSkTypefaceFontProvider.h +1 -1
- package/cpp/api/JsiSkiaContext.h +2 -2
- package/cpp/api/JsiTextureInfo.h +1 -1
- package/cpp/api/JsiVideo.h +2 -2
- package/cpp/api/recorder/Drawings.h +1 -1
- package/cpp/api/recorder/JsiRecorder.h +4 -4
- package/cpp/api/recorder/RNRecorder.h +1 -1
- package/cpp/jsi/ViewProperty.h +1 -1
- package/cpp/rnskia/RNDawnContext.h +13 -0
- package/cpp/rnskia/RNDawnUtils.h +11 -1
- package/cpp/rnskia/RNSkJsiViewApi.h +2 -2
- package/cpp/rnskia/RNSkManager.cpp +88 -2
- package/cpp/rnskia/RNSkPictureView.h +4 -4
- package/cpp/rnskia/RNSkPlatformContext.h +7 -0
- package/cpp/rnskia/RNSkView.h +9 -6
- package/cpp/rnwgpu/ArrayBuffer.h +51 -7
- package/cpp/rnwgpu/api/AppleNativeBuffer.h +22 -0
- package/cpp/rnwgpu/api/Convertors.h +33 -11
- package/cpp/rnwgpu/api/GPUAdapter.cpp +28 -2
- package/cpp/rnwgpu/api/GPUBuffer.h +1 -1
- package/cpp/rnwgpu/api/GPUDevice.cpp +29 -2
- package/cpp/rnwgpu/api/GPUDevice.h +6 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.cpp +139 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.h +52 -2
- package/cpp/rnwgpu/api/GPUQueue.cpp +50 -45
- package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +82 -0
- package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +70 -0
- package/cpp/rnwgpu/api/ImageBitmap.h +62 -0
- package/cpp/rnwgpu/api/NativeBufferUtils.h +87 -0
- package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +4 -1
- package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +1 -1
- package/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h +56 -0
- package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +10 -0
- package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +43 -24
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +9 -9
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +1 -1
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +2 -2
- package/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h +73 -0
- package/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +1 -1
- package/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +1 -1
- package/cpp/skia/include/core/SkRegion.h +10 -5
- package/cpp/skia/include/effects/SkRuntimeEffect.h +2 -2
- package/cpp/skia/include/gpu/graphite/Context.h +1 -1
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
- package/lib/commonjs/skia/types/WebGPU.d.ts +88 -0
- package/lib/commonjs/skia/types/WebGPU.js +6 -0
- package/lib/commonjs/skia/types/WebGPU.js.map +1 -0
- package/lib/commonjs/skia/types/index.d.ts +1 -0
- package/lib/commonjs/skia/types/index.js +11 -0
- package/lib/commonjs/skia/types/index.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +19 -0
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
- package/lib/module/skia/types/WebGPU.d.ts +88 -0
- package/lib/module/skia/types/WebGPU.js +2 -0
- package/lib/module/skia/types/WebGPU.js.map +1 -0
- package/lib/module/skia/types/index.d.ts +1 -0
- package/lib/module/skia/types/index.js +1 -0
- package/lib/module/skia/types/index.js.map +1 -1
- package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
- package/lib/module/skia/web/JsiSkNativeBufferFactory.js +19 -0
- package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkPath.js.map +1 -1
- package/lib/module/web/LoadSkiaWeb.js +1 -2
- package/lib/module/web/LoadSkiaWeb.js.map +1 -1
- package/lib/typescript/lib/commonjs/skia/types/WebGPU.d.ts +1 -0
- package/lib/typescript/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/WebGPU.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/index.d.ts +1 -0
- package/lib/typescript/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
- package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
- package/lib/typescript/src/skia/types/WebGPU.d.ts +88 -0
- package/lib/typescript/src/skia/types/index.d.ts +1 -0
- package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
- package/package.json +10 -8
- package/react-native-skia.podspec +59 -7
- package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +10 -1
- package/src/skia/types/WebGPU.ts +108 -0
- package/src/skia/types/index.ts +1 -0
- package/src/skia/web/JsiSkNativeBufferFactory.ts +20 -0
- package/src/skia/web/JsiSkPath.ts +8 -2
- package/scripts/install-libs.js +0 -133
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["CanvasKitInit","ckSharedPromise","LoadSkiaWeb","opts","
|
|
1
|
+
{"version":3,"names":["CanvasKitInit","ckSharedPromise","LoadSkiaWeb","opts","global","CanvasKit","undefined","LoadSkia"],"sources":["LoadSkiaWeb.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport CanvasKitInit from \"canvaskit-wasm/bin/full/canvaskit\";\nimport type {\n CanvasKit as CanvasKitType,\n CanvasKitInitOptions,\n} from \"canvaskit-wasm\";\n\ndeclare global {\n var CanvasKit: CanvasKitType;\n}\n\nlet ckSharedPromise: Promise<CanvasKitType>;\n\nexport const LoadSkiaWeb = async (opts?: CanvasKitInitOptions) => {\n if (global.CanvasKit !== undefined) {\n return;\n }\n ckSharedPromise = ckSharedPromise ?? CanvasKitInit(opts);\n const CanvasKit = await ckSharedPromise;\n // The CanvasKit API is stored on the global object and used\n // to create the JsiSKApi in the Skia.web.ts file.\n global.CanvasKit = CanvasKit;\n};\n\n// We keep this function for backward compatibility\nexport const LoadSkia = LoadSkiaWeb;\n"],"mappings":"AAAA;AACA;AACA,OAAOA,aAAa,MAAM,mCAAmC;AAU7D,IAAIC,eAAuC;AAE3C,OAAO,MAAMC,WAAW,GAAG,MAAOC,IAA2B,IAAK;EAChE,IAAIC,MAAM,CAACC,SAAS,KAAKC,SAAS,EAAE;IAClC;EACF;EACAL,eAAe,GAAGA,eAAe,aAAfA,eAAe,cAAfA,eAAe,GAAID,aAAa,CAACG,IAAI,CAAC;EACxD,MAAME,SAAS,GAAG,MAAMJ,eAAe;EACvC;EACA;EACAG,MAAM,CAACC,SAAS,GAAGA,SAAS;AAC9B,CAAC;;AAED;AACA,OAAO,MAAME,QAAQ,GAAGL,WAAW","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const __esModule: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const __esModule: boolean;
|
|
2
2
|
export class JsiSkNativeBufferFactory extends _Host.Host {
|
|
3
3
|
MakeFromImage(image: any): OffscreenCanvas;
|
|
4
|
+
MakeTestBuffer(width: any, height: any): OffscreenCanvas;
|
|
4
5
|
Release(_nativeBuffer: any): void;
|
|
5
6
|
}
|
|
6
7
|
import _Host = require("./Host");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -14,7 +14,16 @@ export interface NativeBufferFactory {
|
|
|
14
14
|
*/
|
|
15
15
|
MakeFromImage: (image: SkImage) => NativeBuffer;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Create a native buffer of the given size filled with a procedural test
|
|
18
|
+
* pattern (RGB gradient + diagonal stripes), entirely on the CPU. Useful for
|
|
19
|
+
* examples and tests that need a buffer to feed into
|
|
20
|
+
* `GPUDevice.importExternalTexture` without a camera/video source. Release it
|
|
21
|
+
* with `Release`.
|
|
22
|
+
*/
|
|
23
|
+
MakeTestBuffer: (width: number, height: number) => NativeBuffer;
|
|
24
|
+
/**
|
|
25
|
+
* Release a native buffer that was created with `MakeFromImage` or
|
|
26
|
+
* `MakeTestBuffer`.
|
|
18
27
|
*/
|
|
19
28
|
Release: (nativeBuffer: NativeBuffer) => void;
|
|
20
29
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { NativeBuffer } from "./NativeBuffer";
|
|
2
|
+
/**
|
|
3
|
+
* Descriptor for {@link GPUDevice.importExternalTexture} when the source is a
|
|
4
|
+
* Skia NativeBuffer (Skia has no WebCodecs `VideoFrame`).
|
|
5
|
+
*
|
|
6
|
+
* `source` is the handle returned by `Skia.NativeBuffer.MakeFromImage`: a
|
|
7
|
+
* `CVPixelBufferRef` on Apple, an `AHardwareBuffer*` on Android. The caller
|
|
8
|
+
* owns its lifetime (release it with `Skia.NativeBuffer.Release`) and must keep
|
|
9
|
+
* it alive until the imported texture is destroyed.
|
|
10
|
+
*/
|
|
11
|
+
export interface SkiaGPUExternalTextureDescriptor extends GPUObjectDescriptorBase {
|
|
12
|
+
source: NativeBuffer;
|
|
13
|
+
/** Rotation applied while sampling, in degrees. One of 0 | 90 | 180 | 270. */
|
|
14
|
+
rotation?: number;
|
|
15
|
+
/** Mirror horizontally while sampling. */
|
|
16
|
+
mirrored?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Descriptor for {@link GPUDevice.importSharedTextureMemory}. `handle` is the
|
|
20
|
+
* NativeBuffer returned by `Skia.NativeBuffer.MakeFromImage` (see
|
|
21
|
+
* {@link SkiaGPUExternalTextureDescriptor} for the platform-specific types and
|
|
22
|
+
* lifetime rules).
|
|
23
|
+
*/
|
|
24
|
+
export interface GPUSharedTextureMemoryDescriptor extends GPUObjectDescriptorBase {
|
|
25
|
+
handle: NativeBuffer;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Shared texture memory imported from a platform native buffer via
|
|
29
|
+
* {@link GPUDevice.importSharedTextureMemory}. Create a texture that aliases
|
|
30
|
+
* the memory, then bracket the GPU work that touches it with
|
|
31
|
+
* {@link GPUSharedTextureMemory.beginAccess} / {@link GPUSharedTextureMemory.endAccess}.
|
|
32
|
+
*/
|
|
33
|
+
export interface GPUSharedTextureMemory extends GPUObjectBase {
|
|
34
|
+
/** Create a texture that aliases the shared memory. */
|
|
35
|
+
createTexture(descriptor?: GPUTextureDescriptor): GPUTexture;
|
|
36
|
+
/**
|
|
37
|
+
* Acquire the memory for GPU access. `initialized` marks whether the existing
|
|
38
|
+
* contents should be preserved (pass `true` for an already-rendered frame).
|
|
39
|
+
* Returns `false` if access could not be acquired.
|
|
40
|
+
*/
|
|
41
|
+
beginAccess(texture: GPUTexture, initialized: boolean): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Release the memory after the GPU work that accessed it has been submitted.
|
|
44
|
+
* Returns `false` on failure.
|
|
45
|
+
*/
|
|
46
|
+
endAccess(texture: GPUTexture): boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Dawn-specific toggles, passed via {@link GPUDeviceDescriptor.dawnToggles} to
|
|
50
|
+
* `adapter.requestDevice`. This is a non-spec, Dawn-only extension; see Dawn's
|
|
51
|
+
* toggle list for valid names.
|
|
52
|
+
*/
|
|
53
|
+
export interface GPUDawnTogglesDescriptor {
|
|
54
|
+
enabledToggles?: string[];
|
|
55
|
+
disabledToggles?: string[];
|
|
56
|
+
}
|
|
57
|
+
declare global {
|
|
58
|
+
interface GPUDeviceDescriptor {
|
|
59
|
+
/** Dawn-specific toggles (Skia/Graphite extension, non-spec). */
|
|
60
|
+
dawnToggles?: GPUDawnTogglesDescriptor;
|
|
61
|
+
}
|
|
62
|
+
interface GPUExternalTexture {
|
|
63
|
+
/**
|
|
64
|
+
* Skia extension: end the imported buffer's shared-memory access window and
|
|
65
|
+
* release the underlying resources. Call right after the `queue.submit()`
|
|
66
|
+
* that sampled this texture (never before). Idempotent, and also runs at
|
|
67
|
+
* garbage collection as a fallback.
|
|
68
|
+
*/
|
|
69
|
+
destroy(): void;
|
|
70
|
+
}
|
|
71
|
+
interface GPUDevice {
|
|
72
|
+
/**
|
|
73
|
+
* Skia extension: import a NativeBuffer (from
|
|
74
|
+
* `Skia.NativeBuffer.MakeFromImage`) as a {@link GPUExternalTexture}, sampled
|
|
75
|
+
* with `texture_external` in WGSL. The returned texture owns the
|
|
76
|
+
* shared-memory access window; call `destroy()` on it after the sampling
|
|
77
|
+
* `queue.submit()`.
|
|
78
|
+
*/
|
|
79
|
+
importExternalTexture(descriptor: SkiaGPUExternalTextureDescriptor): GPUExternalTexture;
|
|
80
|
+
/**
|
|
81
|
+
* Skia extension: import a NativeBuffer (from
|
|
82
|
+
* `Skia.NativeBuffer.MakeFromImage`) as {@link GPUSharedTextureMemory}, the
|
|
83
|
+
* lower-level path that lets you create an aliasing texture and manage the
|
|
84
|
+
* begin/end access window yourself.
|
|
85
|
+
*/
|
|
86
|
+
importSharedTextureMemory(descriptor: GPUSharedTextureMemoryDescriptor): GPUSharedTextureMemory;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -4,5 +4,6 @@ import { Host } from "./Host";
|
|
|
4
4
|
export declare class JsiSkNativeBufferFactory extends Host implements NativeBufferFactory {
|
|
5
5
|
constructor(CanvasKit: CanvasKit);
|
|
6
6
|
MakeFromImage(image: SkImage): NativeBuffer;
|
|
7
|
+
MakeTestBuffer(width: number, height: number): NativeBuffer;
|
|
7
8
|
Release(_nativeBuffer: NativeBuffer): void;
|
|
8
9
|
}
|
package/package.json
CHANGED
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
"provenance": true
|
|
6
6
|
},
|
|
7
7
|
"bin": {
|
|
8
|
-
"install-skia": "scripts/install-libs.js",
|
|
9
8
|
"setup-skia-web": "scripts/setup-canvaskit.js"
|
|
10
9
|
},
|
|
11
10
|
"title": "React Native Skia",
|
|
12
|
-
"version": "2.6.
|
|
11
|
+
"version": "2.6.5",
|
|
13
12
|
"description": "High-performance React Native Graphics using Skia",
|
|
14
13
|
"main": "lib/module/index.js",
|
|
15
14
|
"react-native": "src/index.ts",
|
|
@@ -17,7 +16,6 @@
|
|
|
17
16
|
"types": "lib/typescript/index.d.ts",
|
|
18
17
|
"files": [
|
|
19
18
|
"scripts/setup-canvaskit.js",
|
|
20
|
-
"scripts/install-libs.js",
|
|
21
19
|
"src/**",
|
|
22
20
|
"lib/**",
|
|
23
21
|
"!**/__tests__/**",
|
|
@@ -37,7 +35,6 @@
|
|
|
37
35
|
"dist/**"
|
|
38
36
|
],
|
|
39
37
|
"scripts": {
|
|
40
|
-
"postinstall": "node scripts/install-libs.js",
|
|
41
38
|
"lint": "eslint . --ext .ts,.tsx --max-warnings 0 --cache --fix",
|
|
42
39
|
"tsc": "tsc --noEmit",
|
|
43
40
|
"test": "jest",
|
|
@@ -47,8 +44,8 @@
|
|
|
47
44
|
"clean-skia": "yarn rimraf ./libs && yarn rimraf ../../externals/skia/out",
|
|
48
45
|
"build-skia": "tsx ./scripts/build-skia.ts",
|
|
49
46
|
"copy-skia-headers": "tsx ./scripts/copy-skia-headers.ts",
|
|
47
|
+
"install-skia": "tsx ./scripts/install-skia.ts",
|
|
50
48
|
"install-skia-graphite": "tsx ./scripts/install-skia-graphite.ts",
|
|
51
|
-
"install-skia": "node scripts/install-libs.js",
|
|
52
49
|
"clang-format": "yarn clang-format-ios && yarn clang-format-android && yarn clang-format-common",
|
|
53
50
|
"clang-format-ios": "find apple/ -iname '*.h' -o -iname '*.mm' -o -iname '*.cpp' | xargs clang-format -i",
|
|
54
51
|
"clang-format-android": "find android/cpp/ -iname '*.h' -o -iname '*.m' -o -iname '*.cpp' | xargs clang-format -i",
|
|
@@ -92,8 +89,13 @@
|
|
|
92
89
|
}
|
|
93
90
|
},
|
|
94
91
|
"devDependencies": {
|
|
95
|
-
"@babel/plugin-
|
|
92
|
+
"@babel/plugin-transform-class-properties": "^7.28.0",
|
|
96
93
|
"@babel/plugin-transform-explicit-resource-management": "^7.28.0",
|
|
94
|
+
"@babel/plugin-transform-nullish-coalescing-operator": "^7.28.0",
|
|
95
|
+
"@babel/preset-env": "^7.28.0",
|
|
96
|
+
"@babel/preset-flow": "^7.28.0",
|
|
97
|
+
"@babel/preset-react": "^7.28.0",
|
|
98
|
+
"@babel/preset-typescript": "^7.28.0",
|
|
97
99
|
"@blazediff/core": "^1.4.0",
|
|
98
100
|
"@semantic-release/commit-analyzer": "^13.0.0",
|
|
99
101
|
"@semantic-release/exec": "^7.0.3",
|
|
@@ -121,11 +123,11 @@
|
|
|
121
123
|
"rimraf": "3.0.2",
|
|
122
124
|
"semantic-release": "^24.1.0",
|
|
123
125
|
"semantic-release-yarn": "^3.0.2",
|
|
124
|
-
"tar": "^7.5.
|
|
126
|
+
"tar": "^7.5.16",
|
|
125
127
|
"ts-jest": "29.4.3",
|
|
126
128
|
"tsx": "^4.21.0",
|
|
127
129
|
"typescript": "^5.2.2",
|
|
128
|
-
"ws": "8.
|
|
130
|
+
"ws": "8.21.0"
|
|
129
131
|
},
|
|
130
132
|
"dependencies": {
|
|
131
133
|
"canvaskit-wasm": "0.41.0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @shopify/react-native-skia.podspec
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "fileutils"
|
|
4
5
|
|
|
5
6
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
6
7
|
|
|
@@ -8,6 +9,55 @@ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
|
8
9
|
use_graphite = File.exist?(File.join(__dir__, 'libs', '.graphite'))
|
|
9
10
|
puts "-- SK_GRAPHITE: #{use_graphite ? 'ON' : 'OFF'} (detected via libs/.graphite marker file)"
|
|
10
11
|
|
|
12
|
+
# Resolve a node package directory using Node's own module resolution
|
|
13
|
+
# (mirrors `require.resolve(pkg/package.json)`). Returns nil if it can't be found.
|
|
14
|
+
# Defined as a lambda (not a `def`) because CocoaPods evaluates the podspec inside
|
|
15
|
+
# the `Pod` module, where top-level methods are not reachable at the call site.
|
|
16
|
+
resolve_node_package = lambda do |name, base_dir|
|
|
17
|
+
script = "process.stdout.write(require('path').dirname(require.resolve('#{name}/package.json')))"
|
|
18
|
+
dir = Dir.chdir(base_dir) { `node -e "#{script}" 2>/dev/null`.strip }
|
|
19
|
+
dir.empty? ? nil : dir
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Copy the prebuilt xcframeworks from the Skia npm packages into libs/<platform>.
|
|
23
|
+
#
|
|
24
|
+
# This replaces what the old npm `postinstall` script used to do. We do it here, at
|
|
25
|
+
# `pod install` time, so we no longer rely on a lifecycle script. CocoaPods always
|
|
26
|
+
# re-evaluates the podspec for path-based pods, so this runs on every install; to keep
|
|
27
|
+
# it cache-friendly we stamp the copied package version into libs/<platform>/.version
|
|
28
|
+
# and skip the copy when it already matches. On a version bump the frameworks are
|
|
29
|
+
# re-copied and CocoaPods picks up the change. This is best-effort: if `pod install`
|
|
30
|
+
# does not detect the change, a clean reinstall fixes it (acceptable until the upcoming
|
|
31
|
+
# Swift Package Manager migration).
|
|
32
|
+
install_apple_skia_libs = lambda do |base_dir|
|
|
33
|
+
{ 'ios' => 'react-native-skia-apple-ios',
|
|
34
|
+
'macos' => 'react-native-skia-apple-macos',
|
|
35
|
+
'tvos' => 'react-native-skia-apple-tvos' }.each do |platform, pkg_name|
|
|
36
|
+
pkg_dir = resolve_node_package.call(pkg_name, base_dir)
|
|
37
|
+
next if pkg_dir.nil?
|
|
38
|
+
|
|
39
|
+
src = File.join(pkg_dir, 'libs')
|
|
40
|
+
next unless Dir.exist?(src) && !Dir.glob(File.join(src, '*.xcframework')).empty?
|
|
41
|
+
|
|
42
|
+
version = JSON.parse(File.read(File.join(pkg_dir, 'package.json')))['version'].to_s
|
|
43
|
+
dest = File.join(base_dir, 'libs', platform)
|
|
44
|
+
marker = File.join(dest, '.version')
|
|
45
|
+
|
|
46
|
+
# Already up to date: leave the files untouched so CocoaPods keeps its cache.
|
|
47
|
+
next if File.exist?(marker) && File.read(marker).strip == version
|
|
48
|
+
|
|
49
|
+
Pod::UI.puts "react-native-skia: installing #{platform} Skia frameworks (#{version})"
|
|
50
|
+
FileUtils.rm_rf(dest)
|
|
51
|
+
FileUtils.mkdir_p(dest)
|
|
52
|
+
Dir.glob(File.join(src, '*.xcframework')).each { |xcf| FileUtils.cp_r(xcf, dest) }
|
|
53
|
+
File.write(marker, version)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Graphite downloads its binaries directly into libs/; only the default build needs
|
|
58
|
+
# the npm packages copied in.
|
|
59
|
+
install_apple_skia_libs.call(__dir__) unless use_graphite
|
|
60
|
+
|
|
11
61
|
# Set preprocessor definitions based on GRAPHITE flag
|
|
12
62
|
preprocessor_defs = use_graphite ?
|
|
13
63
|
'$(inherited) SK_GRAPHITE=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1' :
|
|
@@ -21,22 +71,24 @@ framework_names = ['libskia', 'libsvg', 'libskshaper', 'libskparagraph',
|
|
|
21
71
|
# Add Dawn library for Graphite builds (contains dawn::native symbols)
|
|
22
72
|
framework_names += ['libdawn_combined'] if use_graphite
|
|
23
73
|
|
|
24
|
-
# Verify that prebuilt binaries
|
|
74
|
+
# Verify that the prebuilt binaries are available (copied in above, or downloaded by
|
|
75
|
+
# install-skia-graphite for Graphite builds).
|
|
25
76
|
unless Dir.exist?(File.join(__dir__, 'libs', 'ios')) && Dir.exist?(File.join(__dir__, 'libs', 'macos'))
|
|
26
77
|
Pod::UI.warn "#{'-' * 72}"
|
|
27
78
|
Pod::UI.warn "react-native-skia: Skia prebuilt binaries not found in libs/!"
|
|
28
79
|
Pod::UI.warn ""
|
|
29
|
-
Pod::UI.warn "
|
|
30
|
-
Pod::UI.warn "
|
|
80
|
+
Pod::UI.warn "Make sure dependencies are installed (yarn install / npm install) so that"
|
|
81
|
+
Pod::UI.warn "the react-native-skia-apple-* packages are present, then run `pod install` again."
|
|
31
82
|
Pod::UI.warn "#{'-' * 72}"
|
|
32
|
-
raise "react-native-skia: Skia prebuilt binaries not found. Run `
|
|
83
|
+
raise "react-native-skia: Skia prebuilt binaries not found. Run `yarn install` then `pod install` to fix this."
|
|
33
84
|
end
|
|
34
85
|
|
|
35
86
|
# Build platform-specific framework paths (relative to pod's libs directory)
|
|
36
|
-
# xcframeworks are copied into libs/ by
|
|
87
|
+
# xcframeworks are copied into libs/ by install_apple_skia_libs above (default build)
|
|
88
|
+
# or downloaded by install-skia-graphite (Graphite build).
|
|
37
89
|
ios_frameworks = framework_names.map { |f| "libs/ios/#{f}.xcframework" }
|
|
38
90
|
osx_frameworks = framework_names.map { |f| "libs/macos/#{f}.xcframework" }
|
|
39
|
-
# tvOS frameworks - check if libs/tvos/ exists (populated
|
|
91
|
+
# tvOS frameworks - check if libs/tvos/ exists (only populated for the default build)
|
|
40
92
|
tvos_frameworks = if use_graphite || !Dir.exist?(File.join(__dir__, 'libs', 'tvos'))
|
|
41
93
|
[]
|
|
42
94
|
else
|
|
@@ -65,7 +117,7 @@ Pod::Spec.new do |s|
|
|
|
65
117
|
'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_defs,
|
|
66
118
|
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
|
|
67
119
|
'DEFINES_MODULE' => 'YES',
|
|
68
|
-
"HEADER_SEARCH_PATHS" => '"$(PODS_TARGET_SRCROOT)/cpp
|
|
120
|
+
"HEADER_SEARCH_PATHS" => '"$(PODS_TARGET_SRCROOT)/cpp"/** "$(PODS_TARGET_SRCROOT)/cpp" "$(PODS_TARGET_SRCROOT)/cpp/skia" "$(PODS_TARGET_SRCROOT)/cpp/dawn/include"'
|
|
69
121
|
}
|
|
70
122
|
|
|
71
123
|
s.frameworks = ['MetalKit', 'AVFoundation', 'AVKit', 'CoreMedia']
|
|
@@ -40,7 +40,16 @@ export interface NativeBufferFactory {
|
|
|
40
40
|
*/
|
|
41
41
|
MakeFromImage: (image: SkImage) => NativeBuffer;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Create a native buffer of the given size filled with a procedural test
|
|
44
|
+
* pattern (RGB gradient + diagonal stripes), entirely on the CPU. Useful for
|
|
45
|
+
* examples and tests that need a buffer to feed into
|
|
46
|
+
* `GPUDevice.importExternalTexture` without a camera/video source. Release it
|
|
47
|
+
* with `Release`.
|
|
48
|
+
*/
|
|
49
|
+
MakeTestBuffer: (width: number, height: number) => NativeBuffer;
|
|
50
|
+
/**
|
|
51
|
+
* Release a native buffer that was created with `MakeFromImage` or
|
|
52
|
+
* `MakeTestBuffer`.
|
|
44
53
|
*/
|
|
45
54
|
Release: (nativeBuffer: NativeBuffer) => void;
|
|
46
55
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { NativeBuffer } from "./NativeBuffer";
|
|
2
|
+
|
|
3
|
+
// Skia's Graphite/Dawn backend extends the standard WebGPU API (typed by
|
|
4
|
+
// @webgpu/types) with a few Skia- and Dawn-specific entry points. These are
|
|
5
|
+
// only available on native (SK_GRAPHITE) builds, reachable through
|
|
6
|
+
// `Skia.getDevice()`.
|
|
7
|
+
//
|
|
8
|
+
// The exported interfaces below describe the descriptors and objects those
|
|
9
|
+
// entry points use; the `declare global` block augments the standard WebGPU
|
|
10
|
+
// interfaces so the new methods are typed without casting to `any`.
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Descriptor for {@link GPUDevice.importExternalTexture} when the source is a
|
|
14
|
+
* Skia NativeBuffer (Skia has no WebCodecs `VideoFrame`).
|
|
15
|
+
*
|
|
16
|
+
* `source` is the handle returned by `Skia.NativeBuffer.MakeFromImage`: a
|
|
17
|
+
* `CVPixelBufferRef` on Apple, an `AHardwareBuffer*` on Android. The caller
|
|
18
|
+
* owns its lifetime (release it with `Skia.NativeBuffer.Release`) and must keep
|
|
19
|
+
* it alive until the imported texture is destroyed.
|
|
20
|
+
*/
|
|
21
|
+
export interface SkiaGPUExternalTextureDescriptor extends GPUObjectDescriptorBase {
|
|
22
|
+
source: NativeBuffer;
|
|
23
|
+
/** Rotation applied while sampling, in degrees. One of 0 | 90 | 180 | 270. */
|
|
24
|
+
rotation?: number;
|
|
25
|
+
/** Mirror horizontally while sampling. */
|
|
26
|
+
mirrored?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Descriptor for {@link GPUDevice.importSharedTextureMemory}. `handle` is the
|
|
31
|
+
* NativeBuffer returned by `Skia.NativeBuffer.MakeFromImage` (see
|
|
32
|
+
* {@link SkiaGPUExternalTextureDescriptor} for the platform-specific types and
|
|
33
|
+
* lifetime rules).
|
|
34
|
+
*/
|
|
35
|
+
export interface GPUSharedTextureMemoryDescriptor extends GPUObjectDescriptorBase {
|
|
36
|
+
handle: NativeBuffer;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Shared texture memory imported from a platform native buffer via
|
|
41
|
+
* {@link GPUDevice.importSharedTextureMemory}. Create a texture that aliases
|
|
42
|
+
* the memory, then bracket the GPU work that touches it with
|
|
43
|
+
* {@link GPUSharedTextureMemory.beginAccess} / {@link GPUSharedTextureMemory.endAccess}.
|
|
44
|
+
*/
|
|
45
|
+
export interface GPUSharedTextureMemory extends GPUObjectBase {
|
|
46
|
+
/** Create a texture that aliases the shared memory. */
|
|
47
|
+
createTexture(descriptor?: GPUTextureDescriptor): GPUTexture;
|
|
48
|
+
/**
|
|
49
|
+
* Acquire the memory for GPU access. `initialized` marks whether the existing
|
|
50
|
+
* contents should be preserved (pass `true` for an already-rendered frame).
|
|
51
|
+
* Returns `false` if access could not be acquired.
|
|
52
|
+
*/
|
|
53
|
+
beginAccess(texture: GPUTexture, initialized: boolean): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Release the memory after the GPU work that accessed it has been submitted.
|
|
56
|
+
* Returns `false` on failure.
|
|
57
|
+
*/
|
|
58
|
+
endAccess(texture: GPUTexture): boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Dawn-specific toggles, passed via {@link GPUDeviceDescriptor.dawnToggles} to
|
|
63
|
+
* `adapter.requestDevice`. This is a non-spec, Dawn-only extension; see Dawn's
|
|
64
|
+
* toggle list for valid names.
|
|
65
|
+
*/
|
|
66
|
+
export interface GPUDawnTogglesDescriptor {
|
|
67
|
+
enabledToggles?: string[];
|
|
68
|
+
disabledToggles?: string[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
declare global {
|
|
72
|
+
interface GPUDeviceDescriptor {
|
|
73
|
+
/** Dawn-specific toggles (Skia/Graphite extension, non-spec). */
|
|
74
|
+
dawnToggles?: GPUDawnTogglesDescriptor;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface GPUExternalTexture {
|
|
78
|
+
/**
|
|
79
|
+
* Skia extension: end the imported buffer's shared-memory access window and
|
|
80
|
+
* release the underlying resources. Call right after the `queue.submit()`
|
|
81
|
+
* that sampled this texture (never before). Idempotent, and also runs at
|
|
82
|
+
* garbage collection as a fallback.
|
|
83
|
+
*/
|
|
84
|
+
destroy(): void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface GPUDevice {
|
|
88
|
+
/**
|
|
89
|
+
* Skia extension: import a NativeBuffer (from
|
|
90
|
+
* `Skia.NativeBuffer.MakeFromImage`) as a {@link GPUExternalTexture}, sampled
|
|
91
|
+
* with `texture_external` in WGSL. The returned texture owns the
|
|
92
|
+
* shared-memory access window; call `destroy()` on it after the sampling
|
|
93
|
+
* `queue.submit()`.
|
|
94
|
+
*/
|
|
95
|
+
importExternalTexture(
|
|
96
|
+
descriptor: SkiaGPUExternalTextureDescriptor
|
|
97
|
+
): GPUExternalTexture;
|
|
98
|
+
/**
|
|
99
|
+
* Skia extension: import a NativeBuffer (from
|
|
100
|
+
* `Skia.NativeBuffer.MakeFromImage`) as {@link GPUSharedTextureMemory}, the
|
|
101
|
+
* lower-level path that lets you create an aliasing texture and manage the
|
|
102
|
+
* begin/end access window yourself.
|
|
103
|
+
*/
|
|
104
|
+
importSharedTextureMemory(
|
|
105
|
+
descriptor: GPUSharedTextureMemoryDescriptor
|
|
106
|
+
): GPUSharedTextureMemory;
|
|
107
|
+
}
|
|
108
|
+
}
|
package/src/skia/types/index.ts
CHANGED
|
@@ -25,6 +25,26 @@ export class JsiSkNativeBufferFactory
|
|
|
25
25
|
return canvas;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
MakeTestBuffer(width: number, height: number): NativeBuffer {
|
|
29
|
+
const pixels = new Uint8ClampedArray(width * height * 4);
|
|
30
|
+
for (let y = 0; y < height; y++) {
|
|
31
|
+
for (let x = 0; x < width; x++) {
|
|
32
|
+
const i = (y * width + x) * 4;
|
|
33
|
+
pixels[i + 0] = Math.floor((x * 255) / Math.max(width - 1, 1));
|
|
34
|
+
pixels[i + 1] = Math.floor((y * 255) / Math.max(height - 1, 1));
|
|
35
|
+
pixels[i + 2] = (x + y) & 0x20 ? 220 : 30;
|
|
36
|
+
pixels[i + 3] = 0xff;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const canvas = new OffscreenCanvas(width, height);
|
|
40
|
+
const ctx = canvas.getContext("2d");
|
|
41
|
+
if (!ctx) {
|
|
42
|
+
throw new Error("Failed to get 2d context from canvas");
|
|
43
|
+
}
|
|
44
|
+
ctx.putImageData(new ImageData(pixels, width, height), 0, 0);
|
|
45
|
+
return canvas;
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
Release(_nativeBuffer: NativeBuffer) {
|
|
29
49
|
// it's a noop on Web
|
|
30
50
|
}
|
|
@@ -447,7 +447,10 @@ export class JsiSkPath
|
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
simplify() {
|
|
450
|
-
warnDeprecatedPathMethod(
|
|
450
|
+
warnDeprecatedPathMethod(
|
|
451
|
+
"simplify",
|
|
452
|
+
"Use Skia.Path.Simplify(path) instead."
|
|
453
|
+
);
|
|
451
454
|
const path = this.asPath();
|
|
452
455
|
const result = path.makeSimplified();
|
|
453
456
|
path.delete();
|
|
@@ -500,7 +503,10 @@ export class JsiSkPath
|
|
|
500
503
|
}
|
|
501
504
|
|
|
502
505
|
stroke(opts?: StrokeOpts) {
|
|
503
|
-
warnDeprecatedPathMethod(
|
|
506
|
+
warnDeprecatedPathMethod(
|
|
507
|
+
"stroke",
|
|
508
|
+
"Use Skia.Path.Stroke(path, opts) instead."
|
|
509
|
+
);
|
|
504
510
|
const path = this.asPath();
|
|
505
511
|
const result = path.makeStroked(
|
|
506
512
|
opts === undefined
|
package/scripts/install-libs.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const fs = require("fs");
|
|
6
|
-
|
|
7
|
-
const useGraphite =
|
|
8
|
-
process.env.SK_GRAPHITE === "1" ||
|
|
9
|
-
(process.env.SK_GRAPHITE || "").toLowerCase() === "true";
|
|
10
|
-
const prefix = useGraphite ? "react-native-skia-graphite" : "react-native-skia";
|
|
11
|
-
const libsDir = path.join(__dirname, "..", "libs");
|
|
12
|
-
|
|
13
|
-
function copySync(src, dest, options) {
|
|
14
|
-
if (!src.includes("*")) {
|
|
15
|
-
return fs.cpSync(src, dest, options);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const wildcardSplit = src.split("*");
|
|
19
|
-
const basePath = wildcardSplit[0];
|
|
20
|
-
const files = fs.readdirSync(basePath);
|
|
21
|
-
files
|
|
22
|
-
.filter((file) => file.endsWith(wildcardSplit[1]))
|
|
23
|
-
.forEach((file) => {
|
|
24
|
-
return fs.cpSync(
|
|
25
|
-
path.join(basePath, file),
|
|
26
|
-
path.join(dest, file),
|
|
27
|
-
options
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// --- Apple platforms ---
|
|
33
|
-
|
|
34
|
-
let iosPackage, macosPackage;
|
|
35
|
-
try {
|
|
36
|
-
iosPackage = path.dirname(
|
|
37
|
-
require.resolve(prefix + "-apple-ios/package.json")
|
|
38
|
-
);
|
|
39
|
-
macosPackage = path.dirname(
|
|
40
|
-
require.resolve(prefix + "-apple-macos/package.json")
|
|
41
|
-
);
|
|
42
|
-
} catch (e) {
|
|
43
|
-
console.error(
|
|
44
|
-
"ERROR: Could not find " +
|
|
45
|
-
prefix +
|
|
46
|
-
"-apple-ios or " +
|
|
47
|
-
prefix +
|
|
48
|
-
"-apple-macos"
|
|
49
|
-
);
|
|
50
|
-
console.error("Make sure you have run yarn install or npm install");
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Verify xcframeworks exist in the iOS package
|
|
55
|
-
const iosXcf = path.join(iosPackage, "libs");
|
|
56
|
-
if (
|
|
57
|
-
!fs.existsSync(iosXcf) ||
|
|
58
|
-
!fs.readdirSync(iosXcf).some((f) => f.endsWith(".xcframework"))
|
|
59
|
-
) {
|
|
60
|
-
console.error(
|
|
61
|
-
"ERROR: Skia prebuilt binaries not found in " + prefix + "-apple-ios!"
|
|
62
|
-
);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
console.log("-- Skia iOS package: " + iosPackage);
|
|
67
|
-
console.log("-- Skia macOS package: " + macosPackage);
|
|
68
|
-
|
|
69
|
-
// Clean and copy Apple frameworks
|
|
70
|
-
fs.rmSync(path.join(libsDir, "ios"), { recursive: true, force: true });
|
|
71
|
-
fs.rmSync(path.join(libsDir, "macos"), { recursive: true, force: true });
|
|
72
|
-
fs.rmSync(path.join(libsDir, "tvos"), { recursive: true, force: true });
|
|
73
|
-
fs.mkdirSync(path.join(libsDir, "ios"), { recursive: true });
|
|
74
|
-
fs.mkdirSync(path.join(libsDir, "macos"), { recursive: true });
|
|
75
|
-
|
|
76
|
-
copySync(iosPackage + "/libs/*.xcframework", path.join(libsDir, "ios"), {
|
|
77
|
-
recursive: true,
|
|
78
|
-
});
|
|
79
|
-
copySync(macosPackage + "/libs/*.xcframework", path.join(libsDir, "macos"), {
|
|
80
|
-
recursive: true,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Handle tvOS (non-Graphite only)
|
|
84
|
-
if (!useGraphite) {
|
|
85
|
-
try {
|
|
86
|
-
const tvosPackage = path.dirname(
|
|
87
|
-
require.resolve(prefix + "-apple-tvos/package.json")
|
|
88
|
-
);
|
|
89
|
-
console.log("-- Skia tvOS package: " + tvosPackage);
|
|
90
|
-
fs.mkdirSync(path.join(libsDir, "tvos"), { recursive: true });
|
|
91
|
-
copySync(tvosPackage + "/libs/*.xcframework", path.join(libsDir, "tvos"), {
|
|
92
|
-
recursive: true,
|
|
93
|
-
});
|
|
94
|
-
} catch (e) {
|
|
95
|
-
console.log("-- tvOS package not found, skipping");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
console.log("-- Copied Apple xcframeworks to libs/");
|
|
100
|
-
|
|
101
|
-
// --- Android ---
|
|
102
|
-
|
|
103
|
-
const androidPackageName = useGraphite
|
|
104
|
-
? "react-native-skia-graphite-android"
|
|
105
|
-
: "react-native-skia-android";
|
|
106
|
-
|
|
107
|
-
let androidPackage;
|
|
108
|
-
try {
|
|
109
|
-
androidPackage = path.dirname(
|
|
110
|
-
require.resolve(androidPackageName + "/package.json")
|
|
111
|
-
);
|
|
112
|
-
} catch (e) {
|
|
113
|
-
console.error("ERROR: Could not find " + androidPackageName);
|
|
114
|
-
console.error("Make sure you have run yarn install or npm install");
|
|
115
|
-
process.exit(1);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const androidSrcLibs = path.join(androidPackage, "libs");
|
|
119
|
-
if (!fs.existsSync(androidSrcLibs)) {
|
|
120
|
-
console.error(
|
|
121
|
-
"ERROR: Skia prebuilt binaries not found in " + androidPackageName + "!"
|
|
122
|
-
);
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
console.log("-- Skia Android package: " + androidPackage);
|
|
127
|
-
|
|
128
|
-
// Copy Android libs (per-ABI static libraries)
|
|
129
|
-
const androidDest = path.join(libsDir, "android");
|
|
130
|
-
fs.rmSync(androidDest, { recursive: true, force: true });
|
|
131
|
-
copySync(androidSrcLibs, androidDest, { recursive: true });
|
|
132
|
-
|
|
133
|
-
console.log("-- Copied Android libs to libs/android/");
|