diff --git a/android/build.gradle b/android/build.gradle index 5a8e945b..74fcd75e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -5,7 +5,14 @@ def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } +def isNewArchitectureEnabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + apply plugin: 'com.android.library' +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} android { @@ -23,6 +30,11 @@ android { targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) versionCode 1 versionName "1.0" + buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()) + } + + buildFeatures { + buildConfig true } } diff --git a/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java b/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java index 9faf7dae..ef7a18d0 100644 --- a/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java +++ b/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java @@ -16,7 +16,12 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.UIManager; +import com.facebook.react.fabric.FabricUIManager; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import com.facebook.react.uimanager.UIManagerHelper; import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.common.UIManagerType; import java.io.File; import java.io.FilenameFilter; @@ -29,7 +34,7 @@ import fr.greweb.reactnativeviewshot.ViewShot.Formats; import fr.greweb.reactnativeviewshot.ViewShot.Results; -public class RNViewShotModule extends ReactContextBaseJavaModule { +public class RNViewShotModule extends ReactContextBaseJavaModule implements TurboModule { public static final String RNVIEW_SHOT = "RNViewShot"; @@ -71,7 +76,8 @@ public void releaseCapture(String uri) { } @ReactMethod - public void captureRef(int tag, ReadableMap options, Promise promise) { + public void captureRef(double tagFromJs, ReadableMap options, Promise promise) { + int tag = (int) tagFromJs; final ReactApplicationContext context = getReactApplicationContext(); final DisplayMetrics dm = context.getResources().getDisplayMetrics(); @@ -99,13 +105,19 @@ public void captureRef(int tag, ReadableMap options, Promise promise) { } final Activity activity = getCurrentActivity(); - final UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class); - - uiManager.addUIBlock(new ViewShot( + ViewShot uiBlock = new ViewShot( tag, extension, imageFormat, quality, scaleWidth, scaleHeight, outputFile, resultStreamFormat, - snapshotContentContainer, reactContext, activity, handleGLSurfaceView, promise, executor) + snapshotContentContainer, reactContext, activity, handleGLSurfaceView, promise, executor ); + + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + UIManager uiManager = UIManagerHelper.getUIManager(context, UIManagerType.FABRIC); + ((FabricUIManager)uiManager).addUIBlock(uiBlock); + } else { + final UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class); + uiManager.addUIBlock(uiBlock); + } } catch (final Throwable ex) { Log.e(RNVIEW_SHOT, "Failed to snapshot view tag " + tag, ex); promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag " + tag); diff --git a/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotPackage.java b/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotPackage.java index 477a15e0..1f2abed3 100644 --- a/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotPackage.java +++ b/android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotPackage.java @@ -1,29 +1,44 @@ package fr.greweb.reactnativeviewshot; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import com.facebook.react.ReactPackage; +import com.facebook.react.TurboReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.ViewManager; -import com.facebook.react.bridge.JavaScriptModule; -public class RNViewShotPackage implements ReactPackage { - @Override - public List createNativeModules(ReactApplicationContext reactContext) { - return Arrays.asList(new RNViewShotModule(reactContext)); - } +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; - // Deprecated RN 0.47 - // @Override - public List> createJSModules() { - return Collections.emptyList(); - } +import java.util.HashMap; +import java.util.Map; - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - return Collections.emptyList(); +public class RNViewShotPackage extends TurboReactPackage { + @Nullable + @Override + public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactApplicationContext) { + if (name.equals(RNViewShotModule.RNVIEW_SHOT)) { + return new RNViewShotModule(reactApplicationContext); + } else { + return null; } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + moduleInfos.put( + RNViewShotModule.RNVIEW_SHOT, + new ReactModuleInfo( + RNViewShotModule.RNVIEW_SHOT, + RNViewShotModule.RNVIEW_SHOT, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + )); + return moduleInfos; + }; + } } \ No newline at end of file diff --git a/android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java b/android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java index 20e29e2e..ce81dda6 100644 --- a/android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java +++ b/android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java @@ -26,6 +26,7 @@ import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.fabric.interop.UIBlockViewResolver; import com.facebook.react.uimanager.NativeViewHierarchyManager; import com.facebook.react.uimanager.UIBlock; @@ -57,7 +58,7 @@ /** * Snapshot utility class allow to screenshot a view. */ -public class ViewShot implements UIBlock { +public class ViewShot implements UIBlock, com.facebook.react.fabric.interop.UIBlock { //region Constants /** * Tag fort Class logs. @@ -183,6 +184,17 @@ public ViewShot( //region Overrides @Override public void execute(final NativeViewHierarchyManager nativeViewHierarchyManager) { + executeImpl(nativeViewHierarchyManager, null); + } + + @Override + public void execute(@NonNull UIBlockViewResolver uiBlockViewResolver) { + executeImpl(null, uiBlockViewResolver); + } + //endregion + + //region Implementation + private void executeImpl(final NativeViewHierarchyManager nativeViewHierarchyManager, final UIBlockViewResolver uiBlockViewResolver) { executor.execute(new Runnable () { @Override public void run() { @@ -191,6 +203,8 @@ public void run() { if (tag == -1) { view = currentActivity.getWindow().getDecorView().findViewById(android.R.id.content); + } else if (uiBlockViewResolver != null) { + view = uiBlockViewResolver.resolveView(tag); } else { view = nativeViewHierarchyManager.resolveView(tag); } @@ -221,9 +235,7 @@ public void run() { } }); } - //endregion - //region Implementation private void saveToTempFileOnDevice(@NonNull final View view) throws IOException { final FileOutputStream fos = new FileOutputStream(output); captureView(view, fos); diff --git a/package.json b/package.json index 8ceb9a42..54ebe41a 100644 --- a/package.json +++ b/package.json @@ -30,5 +30,13 @@ "flow-bin": "^0.170.0", "html-webpack-plugin": "^5.5.1", "react-native-windows": "^0.63.16" + }, + "codegenConfig": { + "name": "RNViewShot", + "type": "all", + "jsSrcsDir": "./src/specs", + "android": { + "javaPackageName": "fr.greweb.reactnativeviewshot" + } } } diff --git a/src/RNViewShot.js b/src/RNViewShot.js index 0caa0f59..19bda72e 100644 --- a/src/RNViewShot.js +++ b/src/RNViewShot.js @@ -1,3 +1,3 @@ //@flow -import { NativeModules } from "react-native"; -export default NativeModules.RNViewShot \ No newline at end of file +import { RNViewShot } from './specs/NativeRNViewShot' +export default RNViewShot \ No newline at end of file diff --git a/src/index.js b/src/index.js index 37a9c4c2..6f0ff55b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ // @flow import React, { Component } from "react"; import { View, Platform, findNodeHandle, StyleProp } from "react-native"; -import RNViewShot from "./RNViewShot"; +import RNViewShot from "./specs/NativeRNViewShot"; import type { ViewStyleProp } from "react-native/Libraries/StyleSheet/StyleSheet"; import type { LayoutEvent } from "react-native/Libraries/Types/CoreEventTypes"; @@ -19,7 +19,7 @@ type Options = { if (!RNViewShot) { console.warn( - "react-native-view-shot: NativeModules.RNViewShot is undefined. Make sure the library is linked on the native side." + "react-native-view-shot: RNViewShot is undefined. Make sure the library is linked on the native side." ); } diff --git a/src/specs/NativeRNViewShot.ts b/src/specs/NativeRNViewShot.ts new file mode 100644 index 00000000..a6f4c009 --- /dev/null +++ b/src/specs/NativeRNViewShot.ts @@ -0,0 +1,10 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + releaseCapture: () => string; + captureRef: (tag: number, options: Object) => Promise + captureScreen: (options: Object) => Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNViewShot'); \ No newline at end of file