From dd841fba5d0c38849fe5b346b9b7c854fd25fde7 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Thu, 31 Aug 2023 09:53:00 +0800 Subject: [PATCH 01/28] Fix wrapObject typeFooDerivedFromBar then unwrapObject typeBar will cause error on iOS, e.g. image.getWidth() will be -1 Summary: the type in JSContext.wrapObject of photoOutput in CameraView.swift is Image the type in JSContextUtils.unwrapObject of getWidth in ImageModule.swift is IImage tested in `RN0.64.3` with `Xcode14.0.1(14A400)` on `macOS Monterey 12.6.5 (21G531)` --- .../ios/Canvas/CanvasRenderingContext2D.swift | 2 +- .../ios/Canvas/DrawingCanvasView.swift | 6 +++--- react-native-pytorch-core/ios/Image/ImageModule.swift | 10 +++++----- react-native-pytorch-core/ios/Media/MediaToBlob.swift | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/react-native-pytorch-core/ios/Canvas/CanvasRenderingContext2D.swift b/react-native-pytorch-core/ios/Canvas/CanvasRenderingContext2D.swift index 90dc40221..badd4268f 100644 --- a/react-native-pytorch-core/ios/Canvas/CanvasRenderingContext2D.swift +++ b/react-native-pytorch-core/ios/Canvas/CanvasRenderingContext2D.swift @@ -519,7 +519,7 @@ class CanvasRenderingContext2D: NSObject { rejecter reject: RCTPromiseRejectBlock) { do { let canvasView = try JSContextUtils.unwrapObject(canvasRef, DrawingCanvasView.self) - let image = try JSContextUtils.unwrapObject(image, IImage.self) + let image = try JSContextUtils.unwrapObject(image, Image.self) if dWidth == -1 && sWidth == -1 { try canvasView.drawImage(image: image, dx: CGFloat(truncating: sx), dy: CGFloat(truncating: sy)) } else if dx == -1 { diff --git a/react-native-pytorch-core/ios/Canvas/DrawingCanvasView.swift b/react-native-pytorch-core/ios/Canvas/DrawingCanvasView.swift index c03f0997b..95c351f85 100644 --- a/react-native-pytorch-core/ios/Canvas/DrawingCanvasView.swift +++ b/react-native-pytorch-core/ios/Canvas/DrawingCanvasView.swift @@ -386,7 +386,7 @@ class DrawingCanvasView: UIView { sublayers.append(newLayer) } - func drawImage(image: IImage, dx: CGFloat, dy: CGFloat) throws { + func drawImage(image: Image, dx: CGFloat, dy: CGFloat) throws { let frame = CGRect(x: dx, y: dy, width: CGFloat(image.getWidth()), height: CGFloat(image.getHeight())) if let bitmap = image.getBitmap() { let newLayer = ImageLayerData(image: bitmap, transform: currentState.transform, frame: frame) @@ -396,7 +396,7 @@ class DrawingCanvasView: UIView { } } - func drawImage(image: IImage, dx: CGFloat, dy: CGFloat, dWidth: CGFloat, dHeight: CGFloat) throws { + func drawImage(image: Image, dx: CGFloat, dy: CGFloat, dWidth: CGFloat, dHeight: CGFloat) throws { let frame = CGRect(x: dx, y: dy, width: dWidth, height: dHeight) if let bitmap = image.getBitmap() { let newLayer = ImageLayerData(image: bitmap, transform: currentState.transform, frame: frame) @@ -406,7 +406,7 @@ class DrawingCanvasView: UIView { } } - func drawImage(image: IImage, + func drawImage(image: Image, sx: CGFloat, sy: CGFloat, sWidth: CGFloat, diff --git a/react-native-pytorch-core/ios/Image/ImageModule.swift b/react-native-pytorch-core/ios/Image/ImageModule.swift index d4601df36..da27206af 100644 --- a/react-native-pytorch-core/ios/Image/ImageModule.swift +++ b/react-native-pytorch-core/ios/Image/ImageModule.swift @@ -77,7 +77,7 @@ public class ImageModule: NSObject { do { let imageData = try JSContextUtils.unwrapObject(imageDataRef, ImageData.self) - var image: IImage + var image: Image if scaled { let bitmap = try imageData.getScaledBitmap() image = Image(image: bitmap) @@ -99,7 +99,7 @@ public class ImageModule: NSObject { resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) { do { - let image = try JSContextUtils.unwrapObject(imageRef, IImage.self) + let image = try JSContextUtils.unwrapObject(imageRef, Image.self) guard let bitmap = image.getBitmap() else { print("Could not get bitmap from image") return @@ -125,7 +125,7 @@ public class ImageModule: NSObject { @objc public func getWidth(_ imageRef: NSDictionary) -> Any { do { - let image = try JSContextUtils.unwrapObject(imageRef, IImage.self) + let image = try JSContextUtils.unwrapObject(imageRef, Image.self) return NSNumber(value: Float(image.getWidth())) } catch { print("Invalid image reference in getWidth") @@ -136,7 +136,7 @@ public class ImageModule: NSObject { @objc public func getHeight(_ imageRef: NSDictionary) -> Any { do { - let image = try JSContextUtils.unwrapObject(imageRef, IImage.self) + let image = try JSContextUtils.unwrapObject(imageRef, Image.self) return NSNumber(value: Float(image.getHeight())) } catch { print("Invalid image reference in getHeight") @@ -151,7 +151,7 @@ public class ImageModule: NSObject { resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) { do { - let image = try JSContextUtils.unwrapObject(imageRef, IImage.self) + let image = try JSContextUtils.unwrapObject(imageRef, Image.self) let scaledImage = try image.scale(sx: CGFloat(truncating: sx), sy: CGFloat(truncating: sy)) let ref = JSContext.wrapObject(object: scaledImage).getJSRef() resolve(ref) diff --git a/react-native-pytorch-core/ios/Media/MediaToBlob.swift b/react-native-pytorch-core/ios/Media/MediaToBlob.swift index 147873131..a3bb359cc 100644 --- a/react-native-pytorch-core/ios/Media/MediaToBlob.swift +++ b/react-native-pytorch-core/ios/Media/MediaToBlob.swift @@ -26,9 +26,9 @@ public class MediaToBlob: NSObject { public init(refId: String) throws { super.init() let obj = try JSContext.unwrapObject(jsRef: ["ID": refId]) - if obj is IImage { + if obj is Image { // swiftlint:disable:next force_cast - let image = obj as! IImage + let image = obj as! Image imageToBlob(img: image) } else if obj is IAudio { // swiftlint:disable:next force_cast @@ -39,7 +39,7 @@ public class MediaToBlob: NSObject { } } - private func imageToBlob(img: IImage) { + private func imageToBlob(img: Image) { let bitmap = img.getBitmap()! let width = bitmap.width let height = bitmap.height From ef8d59d506b47f43c66262bbe5b5e2404061c3e1 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Tue, 12 Sep 2023 16:11:26 +0800 Subject: [PATCH 02/28] Add CameraModule.java so that await takePicture() 400ms is less than UIManager.dispatchViewManagerCommand 500ms with CameraViewManager.java --- .../pytorch/rn/core/PyTorchCorePackage.java | 2 + .../pytorch/rn/core/camera/CameraModule.java | 57 +++++++++++++++++++ .../pytorch/rn/core/camera/CameraView.java | 24 ++++++++ react-native-pytorch-core/src/CameraView.tsx | 32 ++++++++--- 4 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java diff --git a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/PyTorchCorePackage.java b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/PyTorchCorePackage.java index 325b427c5..ef39dd2d4 100644 --- a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/PyTorchCorePackage.java +++ b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/PyTorchCorePackage.java @@ -15,6 +15,7 @@ import java.util.List; import org.jetbrains.annotations.NotNull; import org.pytorch.rn.core.audio.AudioModule; +import org.pytorch.rn.core.camera.CameraModule; import org.pytorch.rn.core.camera.CameraViewManager; import org.pytorch.rn.core.canvas.CanvasRenderingContext2DModule; import org.pytorch.rn.core.canvas.CanvasViewManager; @@ -29,6 +30,7 @@ public class PyTorchCorePackage implements ReactPackage { public List createNativeModules(@NotNull ReactApplicationContext reactContext) { return Arrays.asList( new ModelLoaderModule(reactContext), + new CameraModule(reactContext), new ImageModule(reactContext), new ImageDataModule(reactContext), new CanvasRenderingContext2DModule(reactContext), diff --git a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java new file mode 100644 index 000000000..df6751430 --- /dev/null +++ b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package org.pytorch.rn.core.camera; + +import android.app.Activity; +import android.util.Log; +import android.view.View; +import androidx.annotation.NonNull; + +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; + +@ReactModule(name = "PyTorchCoreCameraModule") +public class CameraModule extends ReactContextBaseJavaModule { + + private static final String TAG = CameraModule.class.getSimpleName(); + + private static final String NAME = "PyTorchCoreCameraModule"; + + public CameraModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @NonNull + @Override + public String getName() { + return NAME; + } + + @ReactMethod + public void takePicture(int reactTag, Promise promise) { + Activity activity = getCurrentActivity(); + View view = activity.findViewById(reactTag); + + try { + CameraView cameraView = (CameraView) view; + cameraView.takePicture(promise); + } catch (Exception e) { + // Sometimes(when RELOAD js of react-native) cause + // `java.lang.ClassCastException: com.facebook.react.views.view.ReactViewGroup cannot be cast to org.pytorch.rn.core.camera.CameraView` + // and crash the APP, then found catch Exception + // and just return here is OK. + + // System.out.println(e); + Log.e(TAG, Log.getStackTraceString(e)); + return; + } + } +} diff --git a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java index 3e0ae0c26..6c52060db 100644 --- a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java +++ b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java @@ -36,6 +36,7 @@ import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.lifecycle.LifecycleOwner; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.google.common.util.concurrent.ListenableFuture; @@ -215,6 +216,29 @@ public void onError(@NonNull ImageCaptureException exception) { } } + protected void takePicture(Promise promise) { + if (mImageCapture != null) { + mImageCapture.takePicture( + ContextCompat.getMainExecutor(mReactContext), + new ImageCapture.OnImageCapturedCallback() { + @Override + public void onCaptureSuccess(@NonNull ImageProxy imageProxy) { + super.onCaptureSuccess(imageProxy); + IImage image = new Image(imageProxy, mReactContext.getApplicationContext()); + JSContext.NativeJSRef ref = JSContext.wrapObject(image); + promise.resolve(ref.getJSRef()); + } + + @Override + public void onError(@NonNull ImageCaptureException exception) { + super.onError(exception); + Log.e(TAG, exception.getLocalizedMessage(), exception); + promise.reject(exception); + } + }); + } + } + protected void flipCamera() { if (mPreferredCameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) { mPreferredCameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA; diff --git a/react-native-pytorch-core/src/CameraView.tsx b/react-native-pytorch-core/src/CameraView.tsx index 86a737955..4cb0def6f 100644 --- a/react-native-pytorch-core/src/CameraView.tsx +++ b/react-native-pytorch-core/src/CameraView.tsx @@ -11,6 +11,8 @@ import * as React from 'react'; import { findNodeHandle, requireNativeComponent, + NativeModules, + Platform, UIManager, ViewProps, } from 'react-native'; @@ -116,6 +118,10 @@ const nativeCameraViewName = 'PyTorchCoreCameraView'; const PyTorchCoreCameraView = requireNativeComponent(nativeCameraViewName); +const nativeCameraModuleName = 'PyTorchCoreCameraModule'; + +const PyTorchCoreCameraModule = NativeModules[nativeCameraModuleName]; + /** * A camera component with [[CameraProps.onCapture]] and [[CameraProps.onFrame]] callbacks. * To programmatically trigger a capture, call the [[takePicture]] function. @@ -195,17 +201,25 @@ export class Camera extends React.PureComponent { * } * ``` */ - public takePicture(): void { + public async takePicture(): void { if (this.cameraRef.current) { - const takePictureCommandId = - UIManager.getViewManagerConfig(nativeCameraViewName).Commands - .takePicture; const cameraViewHandle = findNodeHandle(this.cameraRef.current); - UIManager.dispatchViewManagerCommand( - cameraViewHandle, - takePictureCommandId, - [], - ); + if (Platform.OS === 'android') { + // TODO: also implement ios + const nativeEvent = await PyTorchCoreCameraModule.takePicture(cameraViewHandle); + if (nativeEvent.ID) { + this.handleOnCapture({nativeEvent}); + } + } else { + const takePictureCommandId = + UIManager.getViewManagerConfig(nativeCameraViewName).Commands + .takePicture; + UIManager.dispatchViewManagerCommand( + cameraViewHandle, + takePictureCommandId, + [], + ); + } } } From cb565ac5364d72229c85533b9bbf042e92c5f4de Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Thu, 14 Sep 2023 11:01:53 +0800 Subject: [PATCH 03/28] Support preview instead of photo on Android --- .../pytorch/rn/core/camera/CameraModule.java | 4 +- .../pytorch/rn/core/camera/CameraView.java | 50 ++++++++++++------- react-native-pytorch-core/src/CameraView.tsx | 7 ++- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java index df6751430..2902c429a 100644 --- a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java +++ b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraModule.java @@ -36,13 +36,13 @@ public String getName() { } @ReactMethod - public void takePicture(int reactTag, Promise promise) { + public void takePicture(int reactTag, boolean isPreviewView, Promise promise) { Activity activity = getCurrentActivity(); View view = activity.findViewById(reactTag); try { CameraView cameraView = (CameraView) view; - cameraView.takePicture(promise); + cameraView.takePicture(activity, isPreviewView, promise); } catch (Exception e) { // Sometimes(when RELOAD js of react-native) cause // `java.lang.ClassCastException: com.facebook.react.views.view.ReactViewGroup cannot be cast to org.pytorch.rn.core.camera.CameraView` diff --git a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java index 6c52060db..4c53a70e4 100644 --- a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java +++ b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/camera/CameraView.java @@ -9,6 +9,7 @@ import android.Manifest; import android.animation.ValueAnimator; +import android.app.Activity; import android.content.pm.PackageManager; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; @@ -216,26 +217,37 @@ public void onError(@NonNull ImageCaptureException exception) { } } - protected void takePicture(Promise promise) { + protected void takePicture(Activity activity, boolean isPreviewView, Promise promise) { if (mImageCapture != null) { - mImageCapture.takePicture( - ContextCompat.getMainExecutor(mReactContext), - new ImageCapture.OnImageCapturedCallback() { - @Override - public void onCaptureSuccess(@NonNull ImageProxy imageProxy) { - super.onCaptureSuccess(imageProxy); - IImage image = new Image(imageProxy, mReactContext.getApplicationContext()); - JSContext.NativeJSRef ref = JSContext.wrapObject(image); - promise.resolve(ref.getJSRef()); - } - - @Override - public void onError(@NonNull ImageCaptureException exception) { - super.onError(exception); - Log.e(TAG, exception.getLocalizedMessage(), exception); - promise.reject(exception); - } - }); + if (isPreviewView) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + IImage image = new Image(mPreviewView.getBitmap()); + JSContext.NativeJSRef ref = JSContext.wrapObject(image); + promise.resolve(ref.getJSRef()); + } + }); + } else { + mImageCapture.takePicture( + ContextCompat.getMainExecutor(mReactContext), + new ImageCapture.OnImageCapturedCallback() { + @Override + public void onCaptureSuccess(@NonNull ImageProxy imageProxy) { + super.onCaptureSuccess(imageProxy); + IImage image = new Image(imageProxy, mReactContext.getApplicationContext()); + JSContext.NativeJSRef ref = JSContext.wrapObject(image); + promise.resolve(ref.getJSRef()); + } + + @Override + public void onError(@NonNull ImageCaptureException exception) { + super.onError(exception); + Log.e(TAG, exception.getLocalizedMessage(), exception); + promise.reject(exception); + } + }); + } } } diff --git a/react-native-pytorch-core/src/CameraView.tsx b/react-native-pytorch-core/src/CameraView.tsx index 4cb0def6f..cd640a3c6 100644 --- a/react-native-pytorch-core/src/CameraView.tsx +++ b/react-native-pytorch-core/src/CameraView.tsx @@ -201,12 +201,15 @@ export class Camera extends React.PureComponent { * } * ``` */ - public async takePicture(): void { + // if isPreviewView is true, will use preview instead of photo, + // this can reduce 400ms to 100ms, but since preview will delay + // some from real target, maybe it's nonsense, so default false + public async takePicture(isPreviewView: boolean = false): void { if (this.cameraRef.current) { const cameraViewHandle = findNodeHandle(this.cameraRef.current); if (Platform.OS === 'android') { // TODO: also implement ios - const nativeEvent = await PyTorchCoreCameraModule.takePicture(cameraViewHandle); + const nativeEvent = await PyTorchCoreCameraModule.takePicture(cameraViewHandle, isPreviewView); if (nativeEvent.ID) { this.handleOnCapture({nativeEvent}); } From 5969a5bea6b3bb8601d467e993b87845072ae20d Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Fri, 15 Dec 2023 10:06:42 +0800 Subject: [PATCH 04/28] Pass `bob build` --- react-native-pytorch-core/src/CameraView.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/react-native-pytorch-core/src/CameraView.tsx b/react-native-pytorch-core/src/CameraView.tsx index cd640a3c6..cadb0ffc2 100644 --- a/react-native-pytorch-core/src/CameraView.tsx +++ b/react-native-pytorch-core/src/CameraView.tsx @@ -204,12 +204,15 @@ export class Camera extends React.PureComponent { // if isPreviewView is true, will use preview instead of photo, // this can reduce 400ms to 100ms, but since preview will delay // some from real target, maybe it's nonsense, so default false - public async takePicture(isPreviewView: boolean = false): void { + public async takePicture(isPreviewView: boolean = false): Promise { if (this.cameraRef.current) { const cameraViewHandle = findNodeHandle(this.cameraRef.current); if (Platform.OS === 'android') { // TODO: also implement ios - const nativeEvent = await PyTorchCoreCameraModule.takePicture(cameraViewHandle, isPreviewView); + const nativeEvent = await PyTorchCoreCameraModule.takePicture( + cameraViewHandle, + isPreviewView, + ); if (nativeEvent.ID) { this.handleOnCapture({nativeEvent}); } From ad9cc4e68a9c21f217181043377e610a78ae2c36 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Fri, 15 Dec 2023 10:10:08 +0800 Subject: [PATCH 05/28] Change package name to @flyskywhy/react-native-pytorch-core --- react-native-pytorch-core/README.md | 2 +- react-native-pytorch-core/package.json | 2 +- react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts | 2 +- react-native-pytorch-core/src/torchlive/media.ts | 2 +- react-native-pytorch-core/tsconfig.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/react-native-pytorch-core/README.md b/react-native-pytorch-core/README.md index bc7e3cac0..52f36a189 100644 --- a/react-native-pytorch-core/README.md +++ b/react-native-pytorch-core/README.md @@ -28,7 +28,7 @@ import { Tensor, torch, torchvision, -} from 'react-native-pytorch-core'; +} from '@flyskywhy/react-native-pytorch-core'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; // Alias for torchvision transforms diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 7ff0bf848..944fc5b01 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,5 +1,5 @@ { - "name": "react-native-pytorch-core", + "name": "@flyskywhy/react-native-pytorch-core", "version": "0.0.0", "description": "PyTorch core library for React Native", "main": "lib/commonjs/index", diff --git a/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts b/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts index d023f69a6..9dd944256 100644 --- a/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts +++ b/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts @@ -15,7 +15,7 @@ import { } from '@expo/config-plugins'; // Keeping the name, and version in sync with it's package. -const pkg = require('react-native-pytorch-core/package.json'); +const pkg = require('@flyskywhy/react-native-pytorch-core/package.json'); type Props = {}; diff --git a/react-native-pytorch-core/src/torchlive/media.ts b/react-native-pytorch-core/src/torchlive/media.ts index d5fae2b07..bce642d59 100644 --- a/react-native-pytorch-core/src/torchlive/media.ts +++ b/react-native-pytorch-core/src/torchlive/media.ts @@ -7,7 +7,7 @@ * @format */ -import type {Tensor} from 'react-native-pytorch-core'; +import type {Tensor} from '@flyskywhy/react-native-pytorch-core'; import type {NativeJSRef} from '../NativeJSRef'; import type {Image} from '../ImageModule'; diff --git a/react-native-pytorch-core/tsconfig.json b/react-native-pytorch-core/tsconfig.json index b3db08f34..666893fd6 100644 --- a/react-native-pytorch-core/tsconfig.json +++ b/react-native-pytorch-core/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "baseUrl": "./", "paths": { - "react-native-pytorch-core": ["./src/index"] + "@flyskywhy/react-native-pytorch-core": ["./src/index"] }, "allowUnreachableCode": false, "allowUnusedLabels": false, From 8740adde0ddef181a7973318a40dab0415a6ed1c Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Fri, 15 Dec 2023 10:23:24 +0800 Subject: [PATCH 06/28] 1.0.0 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 944fc5b01..999e49483 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "@flyskywhy/react-native-pytorch-core", - "version": "0.0.0", + "version": "1.0.0", "description": "PyTorch core library for React Native", "main": "lib/commonjs/index", "module": "lib/module/index", From 537dc201aefe52986da52ae9712bbb0d456e584f Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Fri, 15 Dec 2023 10:34:49 +0800 Subject: [PATCH 07/28] Let @flyskywhy/react-native-pytorch-core be public --- react-native-pytorch-core/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 999e49483..4c602d1fe 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -2,6 +2,7 @@ "name": "@flyskywhy/react-native-pytorch-core", "version": "1.0.0", "description": "PyTorch core library for React Native", + "private": false, "main": "lib/commonjs/index", "module": "lib/module/index", "types": "lib/typescript/index.d.ts", From a5e544b5942fbeda1a23b07666c192f1b963f65c Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Fri, 15 Dec 2023 10:35:11 +0800 Subject: [PATCH 08/28] 1.0.1 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 4c602d1fe..56af24f15 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "@flyskywhy/react-native-pytorch-core", - "version": "1.0.0", + "version": "1.0.1", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", From d2ecb83eaae0cd0f687535d7e37a86342253b469 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 18 Dec 2023 15:16:54 +0800 Subject: [PATCH 09/28] Change package name from @flyskywhy/react-native-pytorch-core to react-native-playtorch to fix java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libtorchlive.so --- react-native-pytorch-core/README.md | 2 +- react-native-pytorch-core/package.json | 6 +++--- react-native-pytorch-core/react-native-pytorch-core.podspec | 4 ++-- .../src/expo-plugin/withPyTorchCore.ts | 2 +- react-native-pytorch-core/src/torchlive/media.ts | 2 +- react-native-pytorch-core/tsconfig.json | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/react-native-pytorch-core/README.md b/react-native-pytorch-core/README.md index 52f36a189..ff7ae73a3 100644 --- a/react-native-pytorch-core/README.md +++ b/react-native-pytorch-core/README.md @@ -28,7 +28,7 @@ import { Tensor, torch, torchvision, -} from '@flyskywhy/react-native-pytorch-core'; +} from 'react-native-playtorch'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; // Alias for torchvision transforms diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 56af24f15..a5f586d1f 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,5 +1,5 @@ { - "name": "@flyskywhy/react-native-pytorch-core", + "name": "react-native-playtorch", "version": "1.0.1", "description": "PyTorch core library for React Native", "private": false, @@ -43,13 +43,13 @@ ], "repository": { "type": "git", - "url": "https://github.com/facebookresearch/playtorch.git", + "url": "https://github.com/flyskywhy/playtorch.git", "directory": "react-native-pytorch-core" }, "author": "Meta Platforms, Inc.", "license": "MIT", "bugs": { - "url": "https://github.com/facebookresearch/playtorch/issues" + "url": "https://github.com/flyskywhy/playtorch/issues" }, "homepage": "https://playtorch.dev/", "publishConfig": { diff --git a/react-native-pytorch-core/react-native-pytorch-core.podspec b/react-native-pytorch-core/react-native-pytorch-core.podspec index 30ed1bd0e..a637337ab 100644 --- a/react-native-pytorch-core/react-native-pytorch-core.podspec +++ b/react-native-pytorch-core/react-native-pytorch-core.podspec @@ -8,7 +8,7 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) Pod::Spec.new do |s| - s.name = "react-native-pytorch-core" + s.name = "react-native-playtorch" s.version = package["version"] s.summary = package["description"] s.homepage = package["homepage"] @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = package["author"] s.platforms = { :ios => "12.0" } - s.source = { :git => "https://github.com/facebookresearch/playtorch.git", :tag => "#{s.version}" } + s.source = { :git => "https://github.com/flyskywhy/react-native-playtorch.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift,cpp}", "cxx/src/**/*.{h,cpp}" diff --git a/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts b/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts index 9dd944256..59a736316 100644 --- a/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts +++ b/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts @@ -15,7 +15,7 @@ import { } from '@expo/config-plugins'; // Keeping the name, and version in sync with it's package. -const pkg = require('@flyskywhy/react-native-pytorch-core/package.json'); +const pkg = require('react-native-playtorch/package.json'); type Props = {}; diff --git a/react-native-pytorch-core/src/torchlive/media.ts b/react-native-pytorch-core/src/torchlive/media.ts index bce642d59..28ca2504a 100644 --- a/react-native-pytorch-core/src/torchlive/media.ts +++ b/react-native-pytorch-core/src/torchlive/media.ts @@ -7,7 +7,7 @@ * @format */ -import type {Tensor} from '@flyskywhy/react-native-pytorch-core'; +import type {Tensor} from 'react-native-playtorch'; import type {NativeJSRef} from '../NativeJSRef'; import type {Image} from '../ImageModule'; diff --git a/react-native-pytorch-core/tsconfig.json b/react-native-pytorch-core/tsconfig.json index 666893fd6..b1c6b586f 100644 --- a/react-native-pytorch-core/tsconfig.json +++ b/react-native-pytorch-core/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "baseUrl": "./", "paths": { - "@flyskywhy/react-native-pytorch-core": ["./src/index"] + "react-native-playtorch": ["./src/index"] }, "allowUnreachableCode": false, "allowUnusedLabels": false, From 191ae288072635371a7e20765dbf666d8d45b19b Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 18 Dec 2023 15:20:40 +0800 Subject: [PATCH 10/28] v1.0.0 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index a5f586d1f..cabae42f0 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.1", + "version": "1.0.0", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", From 71a8033b4ba37890c5b9f22d8994df58b96efa5e Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 18 Dec 2023 15:57:57 +0800 Subject: [PATCH 11/28] typo --- react-native-pytorch-core/react-native-pytorch-core.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/react-native-pytorch-core.podspec b/react-native-pytorch-core/react-native-pytorch-core.podspec index a637337ab..47bfe0c66 100644 --- a/react-native-pytorch-core/react-native-pytorch-core.podspec +++ b/react-native-pytorch-core/react-native-pytorch-core.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = package["author"] s.platforms = { :ios => "12.0" } - s.source = { :git => "https://github.com/flyskywhy/react-native-playtorch.git", :tag => "#{s.version}" } + s.source = { :git => "https://github.com/flyskywhy/playtorch.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift,cpp}", "cxx/src/**/*.{h,cpp}" From e38ec454f185b12c12c21da9819a76d5e1db5bb8 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Wed, 20 Dec 2023 11:05:05 +0800 Subject: [PATCH 12/28] Works well on iOS --- react-native-pytorch-core/ios/PyTorchCore-Swift-Header.h | 2 +- ...tive-pytorch-core.podspec => react-native-playtorch.podspec} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename react-native-pytorch-core/{react-native-pytorch-core.podspec => react-native-playtorch.podspec} (100%) diff --git a/react-native-pytorch-core/ios/PyTorchCore-Swift-Header.h b/react-native-pytorch-core/ios/PyTorchCore-Swift-Header.h index e173e40d4..46d571382 100644 --- a/react-native-pytorch-core/ios/PyTorchCore-Swift-Header.h +++ b/react-native-pytorch-core/ios/PyTorchCore-Swift-Header.h @@ -9,4 +9,4 @@ // Imports needed to call Swift from Objective-C // #import -#import "react_native_pytorch_core-Swift.h" +#import "react_native_playtorch-Swift.h" diff --git a/react-native-pytorch-core/react-native-pytorch-core.podspec b/react-native-pytorch-core/react-native-playtorch.podspec similarity index 100% rename from react-native-pytorch-core/react-native-pytorch-core.podspec rename to react-native-pytorch-core/react-native-playtorch.podspec From fed32def5762d3001a20110b920194657ae7641d Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Wed, 20 Dec 2023 13:40:01 +0800 Subject: [PATCH 13/28] v1.0.1 --- react-native-pytorch-core/README.md | 5 +++++ react-native-pytorch-core/package.json | 14 ++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/react-native-pytorch-core/README.md b/react-native-pytorch-core/README.md index ff7ae73a3..a7b6e814b 100644 --- a/react-native-pytorch-core/README.md +++ b/react-native-pytorch-core/README.md @@ -1,5 +1,10 @@ # PyTorch core library for React Native +[![npm version](http://img.shields.io/npm/v/react-native-playtorch.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") +[![npm downloads](http://img.shields.io/npm/dm/react-native-playtorch.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") +[![npm licence](http://img.shields.io/npm/l/react-native-playtorch.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") +[![Platform](https://img.shields.io/badge/platform-ios%20%7C%20android-989898.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") + The PyTorch core library for React Native is part of the PlayTorch project. Please follow the instructions provided on the [PlayTorch website](https://playtorch.dev/) as outlined below! ## 🎉 Getting started with PlayTorch diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index cabae42f0..0f615ca61 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.0", + "version": "1.0.1", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", @@ -14,7 +14,7 @@ "android", "ios", "cxx", - "react-native-pytorch-core.podspec", + "react-native-playtorch.podspec", "!lib/typescript/example", "!android/build", "!ios/build", @@ -37,9 +37,15 @@ "doc": "typedoc --plugin typedoc-plugin-markdown src/index.tsx" }, "keywords": [ - "react-native", + "android", "ios", - "android" + "playtorch", + "pytorch", + "tensor", + "torch", + "torchlive", + "torchvision", + "react-native" ], "repository": { "type": "git", From 52d76ee218ac7f4f969345405a6a6a96d0c877e0 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Wed, 20 Dec 2023 13:47:13 +0800 Subject: [PATCH 14/28] typo --- README.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1c0c0816e..06f3c50e2 100644 --- a/README.md +++ b/README.md @@ -13,19 +13,10 @@ API -

 

- -

- - Current React Native PyTorch Core npm package version. - -

- -

- - PlayTorch is released under the MIT license. - -

+[![npm version](http://img.shields.io/npm/v/react-native-playtorch.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") +[![npm downloads](http://img.shields.io/npm/dm/react-native-playtorch.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") +[![npm licence](http://img.shields.io/npm/l/react-native-playtorch.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") +[![Platform](https://img.shields.io/badge/platform-ios%20%7C%20android-989898.svg?style=flat-square)](https://npmjs.org/package/react-native-playtorch "View this project on npm") ---------------------- From 7c5fe6eea93f9b11d378c080b5e5fae3afab39bd Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Tue, 26 Mar 2024 10:38:30 +0800 Subject: [PATCH 15/28] Support toImageDataDataWeb which export imageData.data with Web RGBA format on Android --- .../org/pytorch/rn/core/image/ImageModule.java | 15 +++++++++++++++ react-native-pytorch-core/src/ImageModule.ts | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/image/ImageModule.java b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/image/ImageModule.java index 34887a487..6c3abb83f 100644 --- a/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/image/ImageModule.java +++ b/react-native-pytorch-core/android/src/main/java/org/pytorch/rn/core/image/ImageModule.java @@ -12,11 +12,13 @@ import android.net.Uri; import android.widget.Toast; import androidx.annotation.NonNull; +import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableArray; import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.views.imagehelper.ImageSource; @@ -27,6 +29,7 @@ import java.io.InputStream; import java.net.URL; import org.pytorch.rn.core.canvas.ImageData; +import org.pytorch.rn.core.image.ImageUtils; import org.pytorch.rn.core.javascript.JSContext; import org.pytorch.rn.core.utils.FileUtils; @@ -187,6 +190,18 @@ public void fromImageData(final ReadableMap imageDataRef, final boolean scaled, promise.resolve(ref.getJSRef()); } + @ReactMethod + public void toImageDataDataWeb(final ReadableMap imageRef, Promise promise) { + IImage image = JSContext.unwrapObject(imageRef); + byte[] bytes = ImageUtils.bitmapToRGBA(image.getBitmap()); + + WritableArray array = Arguments.createArray(); + for (int i = 0; i < bytes.length; i++) { + array.pushInt(bytes[i]); + } + promise.resolve(array); + } + @ReactMethod public void toFile(final ReadableMap imageRef, Promise promise) { try { diff --git a/react-native-pytorch-core/src/ImageModule.ts b/react-native-pytorch-core/src/ImageModule.ts index 31d1db2e2..e1d7283ab 100644 --- a/react-native-pytorch-core/src/ImageModule.ts +++ b/react-native-pytorch-core/src/ImageModule.ts @@ -186,6 +186,11 @@ export const ImageUtil = { return wrapRef(ref); }, + // 2073600 bytes of 720x720 cost 5 seconds to await + async toImageDataDataWeb(image: Image): Promise { + return await ImageModule.toImageDataDataWeb(image); + }, + /** * The `fromJSRef` function returns an [[Image]] by wrapping a [[NativeJSRef]] * object. From 1f73e05b8466bc2a3a29e905c305e8bbda57b6a9 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Wed, 7 Aug 2024 16:46:40 +0800 Subject: [PATCH 16/28] Fix RN0.71 cause `Expected directory '/home/foo/bar/android/../node_modules/react-native/android' to contain exactly one file, however, it contains no files` --- react-native-pytorch-core/android/build.gradle | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/react-native-pytorch-core/android/build.gradle b/react-native-pytorch-core/android/build.gradle index c70681a72..3702acb4f 100644 --- a/react-native-pytorch-core/android/build.gradle +++ b/react-native-pytorch-core/android/build.gradle @@ -109,7 +109,11 @@ dependencies { implementation "org.pytorch:pytorch_android_lite:${pytorchLiteVersion}" //noinspection GradleDynamicVersion - api "com.facebook.react:react-native:+" // From node_modules + if (Integer.parseInt(appRnMinorVersion) < 71) { + api "com.facebook.react:react-native:+" // From node_modules + } else { + implementation("com.facebook.react:react-android") + } //noinspection GradleDynamicVersion extractHeaders("com.facebook.fbjni:fbjni:+:headers") @@ -126,7 +130,7 @@ dependencies { if (Integer.parseInt(appRnMinorVersion) < 69) { def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include "**/**/*.aar" }).singleFile extractJNI(files(rnAAR)) - } else { + } else if (Integer.parseInt(appRnMinorVersion) < 71) { // React Native 0.69 def rnAarMatcher = "**/react-native/**/*${buildType}.aar" def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include rnAarMatcher }).singleFile From 8ae63d2d3542385ac2bebea2fe44b46fc13a2b48 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Wed, 7 Aug 2024 16:48:27 +0800 Subject: [PATCH 17/28] v1.0.2 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 0f615ca61..58f110e8b 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.1", + "version": "1.0.2", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", From e1318542b7b05aac1144a2bcd3b791e6c4b0c1a5 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 09:52:09 +0800 Subject: [PATCH 18/28] Fix compile error `Duplicate class com.facebook.jni.CppException found in modules jetified-fbjni-0.3.0-runtime (com.facebook.fbjni:fbjni:0.3.0) and jetified-fbjni-java-only-0.2 (com.facebook.fbjni:fbjni-java-only:0.2.2)`, ref to https://github.com/facebook/react-native/issues/34328#issuecomment-1207907649 --- react-native-pytorch-core/android/build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/react-native-pytorch-core/android/build.gradle b/react-native-pytorch-core/android/build.gradle index 3702acb4f..80a24e32c 100644 --- a/react-native-pytorch-core/android/build.gradle +++ b/react-native-pytorch-core/android/build.gradle @@ -106,7 +106,13 @@ repositories { dependencies { def pytorchLiteVersion = '1.12.2' - implementation "org.pytorch:pytorch_android_lite:${pytorchLiteVersion}" + if (Integer.parseInt(appRnMinorVersion) < 71) { + implementation "org.pytorch:pytorch_android_lite:${pytorchLiteVersion}" + } else { + implementation ("org.pytorch:pytorch_android_lite:${pytorchLiteVersion}") { + exclude group:'com.facebook.fbjni', module: 'fbjni-java-only' + } + } //noinspection GradleDynamicVersion if (Integer.parseInt(appRnMinorVersion) < 71) { From a05eed1520977a69cec0043fb27594e1ec196e9c Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 10:09:40 +0800 Subject: [PATCH 19/28] Fix Android NDK compile `ld: error: found local symbol '__end__'` --- react-native-pytorch-core/android/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/react-native-pytorch-core/android/build.gradle b/react-native-pytorch-core/android/build.gradle index 80a24e32c..fdc496bcb 100644 --- a/react-native-pytorch-core/android/build.gradle +++ b/react-native-pytorch-core/android/build.gradle @@ -41,6 +41,12 @@ def safeExtGet(prop, fallback) { android { compileSdkVersion safeExtGet('PyTorchCore_compileSdkVersion', Integer.parseInt(appRnMinorVersion) < 68 ? 30 : 31) buildToolsVersion safeExtGet('PyTorchCore_buildToolsVersion', Integer.parseInt(appRnMinorVersion) < 68 ? '30.0.2' : '31.0.0') + + // ndkVersion getExtOrDefault('ndkVersion') + // use below because ndk 22+ version will cause `ld: error: found local symbol '__end__'` + // ref to https://github.com/pytorch/pytorch/issues/51020#issuecomment-1600272599 + ndkVersion "21.4.7075529" + defaultConfig { minSdkVersion safeExtGet('PyTorchCore_minSdkVersion', 21) targetSdkVersion safeExtGet('PyTorchCore_targetSdkVersion', 30) From ce55e974dc4e29622039b04ecf6efc62ab205c6b Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 10:33:36 +0800 Subject: [PATCH 20/28] Add support for react-native 0.71 to fix `CMake Error: The following variables are used in this project, but they are set to NOTFOUND. FBJNI_LIB`, ref to https://github.com/mrousavy/react-native-vision-camera/commit/b82d0e --- .../android/CMakeLists.txt | 114 ++++++++++++------ .../android/build.gradle | 65 ++++++---- 2 files changed, 119 insertions(+), 60 deletions(-) diff --git a/react-native-pytorch-core/android/CMakeLists.txt b/react-native-pytorch-core/android/CMakeLists.txt index 1ddb16180..86f44060d 100644 --- a/react-native-pytorch-core/android/CMakeLists.txt +++ b/react-native-pytorch-core/android/CMakeLists.txt @@ -3,17 +3,31 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +project(PlayTorch) cmake_minimum_required(VERSION 3.4.1) set (CMAKE_VERBOSE_MAKEFILE ON) # This should be matched with the Unit Test Build. Please keep them in sync. See ../cxx/test/CMakeLists.txt set (CMAKE_CXX_STANDARD 14) -set (CMAKE_CXX_FLAGS "-DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_HAVE_MEMRCHR=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_MOBILE=1 -DON_ANDROID -DONANDROID") + +if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71) + include("${NODE_MODULES_DIR}/react-native/ReactAndroid/cmake-utils/folly-flags.cmake") + add_compile_options(${folly_FLAGS}) +else() + set (CMAKE_CXX_FLAGS "-DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_HAVE_MEMRCHR=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_MOBILE=1 -DON_ANDROID -DONANDROID") +endif() set (PACKAGE_NAME "torchlive") set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build) -set (RN_SO_DIR ${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/first-party/react/jni) + +if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71) + # Consume shared libraries and headers from prefabs + find_package(fbjni REQUIRED CONFIG) + find_package(ReactAndroid REQUIRED CONFIG) +else() + set (RN_SO_DIR ${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/first-party/react/jni) +endif() # PyTorch Core shared @@ -60,25 +74,43 @@ add_library( # includes -file (GLOB LIBFBJNI_INCLUDE_DIR "${BUILD_DIR}/fbjni-*-headers.jar/") file (GLOB PYTORCH_INCLUDE_DIRS "${BUILD_DIR}/pytorch_android_lite*.aar/headers") -target_include_directories( - ${PACKAGE_NAME} - PRIVATE - "${LIBFBJNI_INCLUDE_DIR}" - "${NODE_MODULES_DIR}/react-native/React" - "${NODE_MODULES_DIR}/react-native/React/Base" - "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni" - "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni" - "${NODE_MODULES_DIR}/react-native/ReactCommon" - "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker" - "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi" - "${NODE_MODULES_DIR}/react-native/ReactCommon/runtimeexecutor" - "${PYTORCH_INCLUDE_DIRS}" - "../cxx/src" - "src/main/cpp" -) +if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71) + target_include_directories( + ${PACKAGE_NAME} + PRIVATE + "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/react/turbomodule" + "${NODE_MODULES_DIR}/react-native/ReactCommon" + "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker" + "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi" + "${NODE_MODULES_DIR}/react-native/ReactCommon/react/renderer/graphics/platform/cxx" + "${NODE_MODULES_DIR}/react-native/ReactCommon/runtimeexecutor" + "${NODE_MODULES_DIR}/react-native/ReactCommon/yoga" + "${PYTORCH_INCLUDE_DIRS}" + "../cxx/src" + "src/main/cpp" + ) +else() + file (GLOB LIBFBJNI_INCLUDE_DIR "${BUILD_DIR}/fbjni-*-headers.jar/") + + target_include_directories( + ${PACKAGE_NAME} + PRIVATE + "${LIBFBJNI_INCLUDE_DIR}" + "${NODE_MODULES_DIR}/react-native/React" + "${NODE_MODULES_DIR}/react-native/React/Base" + "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni" + "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni" + "${NODE_MODULES_DIR}/react-native/ReactCommon" + "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker" + "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi" + "${NODE_MODULES_DIR}/react-native/ReactCommon/runtimeexecutor" + "${PYTORCH_INCLUDE_DIRS}" + "../cxx/src" + "src/main/cpp" + ) +endif() # find libraries @@ -90,20 +122,21 @@ find_library( log ) -find_library( - FBJNI_LIBRARY - fbjni - PATHS ${LIBRN_DIR} - NO_CMAKE_FIND_ROOT_PATH -) - -find_library( - REACT_NATIVE_JNI_LIB - reactnativejni - PATHS ${LIBRN_DIR} - NO_CMAKE_FIND_ROOT_PATH -) +if(${REACT_NATIVE_MINOR_VERSION} LESS 71) + find_library( + FBJNI_LIBRARY + fbjni + PATHS ${LIBRN_DIR} + NO_CMAKE_FIND_ROOT_PATH + ) + find_library( + REACT_NATIVE_JNI_LIB + reactnativejni + PATHS ${LIBRN_DIR} + NO_CMAKE_FIND_ROOT_PATH + ) +endif() find_library( PYTORCH_LIBRARY @@ -112,8 +145,21 @@ find_library( NO_CMAKE_FIND_ROOT_PATH ) -# For RN 0.66+, use the distributed libjsi.so -if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 66) +if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71) + target_link_libraries( + ${PACKAGE_NAME} + ReactAndroid::folly_runtime + ReactAndroid::glog + ReactAndroid::jsi + ReactAndroid::reactnativejni + fbjni::fbjni + ${PYTORCH_LIBRARY} + ) +elseif(${REACT_NATIVE_MINOR_VERSION} LESS 66) + # JSI lib didn't exist on RN 0.65 and before. Simply omit it. + set (JSI_LIB "") +else() + # For RN 0.66+, use the distributed libjsi.so find_library( JSI_LIB jsi diff --git a/react-native-pytorch-core/android/build.gradle b/react-native-pytorch-core/android/build.gradle index fdc496bcb..a89fa1f7a 100644 --- a/react-native-pytorch-core/android/build.gradle +++ b/react-native-pytorch-core/android/build.gradle @@ -47,6 +47,12 @@ android { // ref to https://github.com/pytorch/pytorch/issues/51020#issuecomment-1600272599 ndkVersion "21.4.7075529" + if (Integer.parseInt(appRnMinorVersion) >= 71) { + buildFeatures { + prefab true + } + } + defaultConfig { minSdkVersion safeExtGet('PyTorchCore_minSdkVersion', 21) targetSdkVersion safeExtGet('PyTorchCore_targetSdkVersion', 30) @@ -73,12 +79,15 @@ android { lintOptions { disable 'GradleCompatible' } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + if (Integer.parseInt(appRnMinorVersion) < 71) { + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } externalNativeBuild { cmake { + // version "3.22.1" path "CMakeLists.txt" } } @@ -120,33 +129,35 @@ dependencies { } } - //noinspection GradleDynamicVersion if (Integer.parseInt(appRnMinorVersion) < 71) { api "com.facebook.react:react-native:+" // From node_modules } else { + //noinspection GradleDynamicVersion implementation("com.facebook.react:react-android") } - //noinspection GradleDynamicVersion - extractHeaders("com.facebook.fbjni:fbjni:+:headers") - //noinspection GradleDynamicVersion - extractJNI("com.facebook.fbjni:fbjni:+") - - def nodeModules = "${rootDir}/../node_modules" - - // For now we use the release version of the jni library - // we will look back on this once we figure out how to - // get the buildType duing configuration stage - def buildType = "release" - - if (Integer.parseInt(appRnMinorVersion) < 69) { - def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include "**/**/*.aar" }).singleFile - extractJNI(files(rnAAR)) - } else if (Integer.parseInt(appRnMinorVersion) < 71) { - // React Native 0.69 - def rnAarMatcher = "**/react-native/**/*${buildType}.aar" - def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include rnAarMatcher }).singleFile - extractJNI(files(rnAAR)) + if (Integer.parseInt(appRnMinorVersion) < 71) { + //noinspection GradleDynamicVersion + extractHeaders("com.facebook.fbjni:fbjni:+:headers") + //noinspection GradleDynamicVersion + extractJNI("com.facebook.fbjni:fbjni:+") + + def nodeModules = "${rootDir}/../node_modules" + + // For now we use the release version of the jni library + // we will look back on this once we figure out how to + // get the buildType duing configuration stage + def buildType = "release" + + if (Integer.parseInt(appRnMinorVersion) < 69) { + def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include "**/**/*.aar" }).singleFile + extractJNI(files(rnAAR)) + } else if (Integer.parseInt(appRnMinorVersion) < 71) { + // React Native 0.69 + def rnAarMatcher = "**/react-native/**/*${buildType}.aar" + def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include rnAarMatcher }).singleFile + extractJNI(files(rnAAR)) + } } extractForNativeBuild("org.pytorch:pytorch_android_lite:${pytorchLiteVersion}") @@ -223,8 +234,10 @@ task extractAARForNativeBuild { def configureCMakeTaskName = Integer.parseInt(appRnMinorVersion) < 68 ? "externalNativeBuild" : "configureCMake" tasks.whenTaskAdded { task -> if (task.name.contains(configureCMakeTaskName)) { - task.dependsOn(extractAARHeaders) task.dependsOn(extractJNIFiles) - task.dependsOn(extractAARForNativeBuild) + if (Integer.parseInt(appRnMinorVersion) < 71) { + task.dependsOn(extractAARHeaders) + task.dependsOn(extractAARForNativeBuild) + } } } From 839e28c8546e8e8f2a822187b86d8c74e1e8336b Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 10:39:40 +0800 Subject: [PATCH 21/28] Just change fbjni from 0.2.2 to 0.3.0 in expo-plugin, maybe not necessory --- react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts b/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts index 59a736316..0f9a68623 100644 --- a/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts +++ b/react-native-pytorch-core/src/expo-plugin/withPyTorchCore.ts @@ -93,7 +93,7 @@ tasks.whenTaskAdded { task -> dependencies { // Used to control the version of libfbjni.so packaged into the APK - extraJNILibs("com.facebook.fbjni:fbjni:0.2.2") + extraJNILibs("com.facebook.fbjni:fbjni:0.3.0") `, ); From 45d82add159e3e4ec002331dccda3271cd047a56 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 10:41:01 +0800 Subject: [PATCH 22/28] v1.0.3 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 58f110e8b..d7eb9a4b7 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.2", + "version": "1.0.3", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", From 08216a88658f65f748abc9e83fe1ba36728d9009 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 14:10:06 +0800 Subject: [PATCH 23/28] Fix `ninja: error: '../../../../build/pytorch_android_lite-1.12.2.aar/jni/arm64-v8a/libpytorch_jni_lite.so', missing and no known rule to make it` --- react-native-pytorch-core/android/build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/react-native-pytorch-core/android/build.gradle b/react-native-pytorch-core/android/build.gradle index a89fa1f7a..e3c5ccfe8 100644 --- a/react-native-pytorch-core/android/build.gradle +++ b/react-native-pytorch-core/android/build.gradle @@ -235,9 +235,7 @@ def configureCMakeTaskName = Integer.parseInt(appRnMinorVersion) < 68 ? "externa tasks.whenTaskAdded { task -> if (task.name.contains(configureCMakeTaskName)) { task.dependsOn(extractJNIFiles) - if (Integer.parseInt(appRnMinorVersion) < 71) { - task.dependsOn(extractAARHeaders) - task.dependsOn(extractAARForNativeBuild) - } + task.dependsOn(extractAARHeaders) + task.dependsOn(extractAARForNativeBuild) } } From 7c3e5817264dc4513f5ae9d46796c81575c31dd0 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 14:10:52 +0800 Subject: [PATCH 24/28] v1.0.4 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index d7eb9a4b7..7278ad165 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.3", + "version": "1.0.4", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", From a8670be23920b7d74290e4c69cd4df9f99010345 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 14:18:54 +0800 Subject: [PATCH 25/28] README.md: Install --- react-native-pytorch-core/README.md | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/react-native-pytorch-core/README.md b/react-native-pytorch-core/README.md index a7b6e814b..20ffb3050 100644 --- a/react-native-pytorch-core/README.md +++ b/react-native-pytorch-core/README.md @@ -18,6 +18,38 @@ Follow the [Getting Started guide](https://playtorch.dev/docs/tutorials/get-star The full documentation for PlayTorch can be found on our [website](https://playtorch.dev/). +## Install +``` +npm install react-native-playtorch +``` + +Modify `android/app/build.gradle`: +``` +android { + .... + packagingOptions { + pickFirst '**/*.so' + } + ... +} +``` +Modify `android/gradle.properties`: +``` +org.gradle.jvmargs=-Xmx4g +``` +Modify `metro.config.js`: +``` +const defaultAssetExts = require('metro-config/src/defaults/defaults') + .assetExts; + +module.exports = { + resolver: { + assetExts: [...defaultAssetExts, 'ptl'], + }, +}; +``` + + ## Example Usage ```javascript From 2bd648e039caf3e3b9079796b01667e0cc500709 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Mon, 12 Aug 2024 14:19:19 +0800 Subject: [PATCH 26/28] v1.0.5 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 7278ad165..93aa9239d 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.4", + "version": "1.0.5", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index", From 8bcbb0c2c5679c70e0416f0a0a5e3aace529a833 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Thu, 15 Aug 2024 16:07:19 +0800 Subject: [PATCH 27/28] Fix run crash on Android [java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__emutls_get_address" referenced by "/data/app/~~Bu6UWdRieDpDrpvvyvNNVQ==/com.foo.bar-w8nusksLnLfSCCsWG3cEkg==/lib/arm64/libfolly_runtime.so](https://github.com/facebook/react-native/issues/43126) --- react-native-pytorch-core/README.md | 39 +++++++++++++++++++ .../android/build.gradle | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/react-native-pytorch-core/README.md b/react-native-pytorch-core/README.md index 20ffb3050..4ede7ead3 100644 --- a/react-native-pytorch-core/README.md +++ b/react-native-pytorch-core/README.md @@ -28,6 +28,7 @@ Modify `android/app/build.gradle`: android { .... packagingOptions { + // doNotStrip "**/libc++_shared.so" pickFirst '**/*.so' } ... @@ -49,6 +50,44 @@ module.exports = { }; ``` +## Patch to fix `__emutls_get_address` crash on Android +If `RN0.71+` and run crash on Android `java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__emutls_get_address" referenced by "/data/app/~~Bu6UWdRieDpDrpvvyvNNVQ==/com.foo.bar-w8nusksLnLfSCCsWG3cEkg==/lib/arm64/libfolly_runtime.so"`, you need (e.g. on Linux) +``` +cd tools/android-sdk/ndk + +mv ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/origin_libc++_shared.so +cp ./23.1.7779620/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/ + +mv ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/origin_libc++_shared.so +cp ./23.1.7779620/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/ + +mv ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/origin_libc++_shared.so +cp ./23.1.7779620/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/ + +mv ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/origin_libc++_shared.so +cp ./23.1.7779620/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/libc++_shared.so ./21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/ +``` +The crash reason is, even the `libc++_shared.so` in `prefab` +``` +readelf -s ~/.gradle/caches/transforms-3/9915f55612e7d9d2d8676faa1872c696/transformed/jetified-react-android-0.71.6-debug/jni/arm64-v8a/libc++_shared.so | grep __emutls_get_address + 374: 00000000000ec5bc 448 FUNC WEAK DEFAULT 16 __emutls_get_address +``` +is `WEAK` not `LOCAL`, but with `pickFirst '**/*.so'`, the `libc++_shared.so` in `.apk` will be picked from `node_modules/react-native-playtorch/android/build/intermediates/library_jni/debug/jni/arm64-v8a/libc++_shared.so`, and +``` +readelf -s node_modules/react-native-playtorch/android/build/intermediates/library_jni/debug/jni/arm64-v8a/libc++_shared.so | grep __emutls_get_address + 3885: 00000000000b60a0 344 FUNC LOCAL DEFAULT 11 __emutls_get_address +``` +is `LOCAL` not `WEAK`. + +If enable `doNotStrip "**/libc++_shared.so"` then extract the `libc++_shared.so` from `.apk`, use `readelf` you will also find it's `LOCAL` not `WEAK`. + +The `libfolly_runtime.so` will call `__emutls_get_address`, if it's `LOCAL`, then run into crash. + +The `__emutls_get_address` in `libc++_shared.so` of `NDK21.4.7075529` is `LOCAL`, and it's `WEAK` for `NDK23.1.7779620`. + +For now, `react-native-playtorch` only can be compiled in `NDK21.4.7075529`. + +So comes the patch above. ## Example Usage diff --git a/react-native-pytorch-core/android/build.gradle b/react-native-pytorch-core/android/build.gradle index e3c5ccfe8..fefdf7c4e 100644 --- a/react-native-pytorch-core/android/build.gradle +++ b/react-native-pytorch-core/android/build.gradle @@ -43,7 +43,7 @@ android { buildToolsVersion safeExtGet('PyTorchCore_buildToolsVersion', Integer.parseInt(appRnMinorVersion) < 68 ? '30.0.2' : '31.0.0') // ndkVersion getExtOrDefault('ndkVersion') - // use below because ndk 22+ version will cause `ld: error: found local symbol '__end__'` + // use below because ndk 22+ version will cause `ld: error: found local symbol '__bss_start'` // ref to https://github.com/pytorch/pytorch/issues/51020#issuecomment-1600272599 ndkVersion "21.4.7075529" From 4f63b11e3f1f37411abc52e0184ac982b14a4376 Mon Sep 17 00:00:00 2001 From: Li Zheng Date: Thu, 15 Aug 2024 16:20:32 +0800 Subject: [PATCH 28/28] v1.0.6 --- react-native-pytorch-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-native-pytorch-core/package.json b/react-native-pytorch-core/package.json index 93aa9239d..b1b7fa0ba 100644 --- a/react-native-pytorch-core/package.json +++ b/react-native-pytorch-core/package.json @@ -1,6 +1,6 @@ { "name": "react-native-playtorch", - "version": "1.0.5", + "version": "1.0.6", "description": "PyTorch core library for React Native", "private": false, "main": "lib/commonjs/index",