build(metro): add web shims for native React Native API compatibility
Add Metro configuration to resolve native-only React Native APIs with web-compatible shims. This enables packages like react-native-pager-view to work on the web platform by providing shim implementations for codegenNativeComponent, codegenNativeCommands, and CodegenTypes that are unavailable in react-native-web. Also simplify Android signing configuration in CI by using standard Gradle property names (MYAPP_UPLOAD_*) and remove the build.gradle patching step.
This commit is contained in:
@@ -154,29 +154,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > android/app/withyou-release-key.keystore
|
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > android/app/withyou-release-key.keystore
|
||||||
|
|
||||||
- name: Patch app/build.gradle with signing config
|
|
||||||
run: |
|
|
||||||
cd android/app
|
|
||||||
python3 -c "
|
|
||||||
import re
|
|
||||||
with open('build.gradle', 'r') as f:
|
|
||||||
content = f.read()
|
|
||||||
release_signing = '''
|
|
||||||
signingConfigs {
|
|
||||||
release {
|
|
||||||
storeFile file(WITHYOU_UPLOAD_STORE_FILE)
|
|
||||||
storePassword WITHYOU_UPLOAD_STORE_PASSWORD
|
|
||||||
keyAlias WITHYOU_UPLOAD_KEY_ALIAS
|
|
||||||
keyPassword WITHYOU_UPLOAD_KEY_PASSWORD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
content = content.replace('signingConfigs {}', release_signing)
|
|
||||||
content = content.replace('signingConfig signingConfigs.debug', 'signingConfig signingConfigs.release')
|
|
||||||
with open('build.gradle', 'w') as f:
|
|
||||||
f.write(content)
|
|
||||||
"
|
|
||||||
|
|
||||||
- name: Configure Gradle with Aliyun Maven mirror
|
- name: Configure Gradle with Aliyun Maven mirror
|
||||||
run: |
|
run: |
|
||||||
cd android
|
cd android
|
||||||
@@ -291,10 +268,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd android
|
cd android
|
||||||
cat >> gradle.properties << SIGNING_PROPS
|
cat >> gradle.properties << SIGNING_PROPS
|
||||||
WITHYOU_UPLOAD_STORE_FILE=withyou-release-key.keystore
|
MYAPP_UPLOAD_STORE_FILE=withyou-release-key.keystore
|
||||||
WITHYOU_UPLOAD_STORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
MYAPP_UPLOAD_STORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||||
WITHYOU_UPLOAD_KEY_ALIAS=withyou-key
|
MYAPP_UPLOAD_KEY_ALIAS=withyou-key
|
||||||
WITHYOU_UPLOAD_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}
|
MYAPP_UPLOAD_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||||
SIGNING_PROPS
|
SIGNING_PROPS
|
||||||
|
|
||||||
- name: Build Android release APK (arm64 only)
|
- name: Build Android release APK (arm64 only)
|
||||||
|
|||||||
BIN
assets/icon.png
BIN
assets/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 895 KiB After Width: | Height: | Size: 522 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 895 KiB After Width: | Height: | Size: 522 KiB |
@@ -19,6 +19,35 @@ config.resolver.alias = {
|
|||||||
// Ensure platform-specific files are resolved correctly
|
// Ensure platform-specific files are resolved correctly
|
||||||
config.resolver.platforms = ['ios', 'android', 'native', 'web'];
|
config.resolver.platforms = ['ios', 'android', 'native', 'web'];
|
||||||
|
|
||||||
|
// Web shims for native-only React Native APIs that don't exist in react-native-web.
|
||||||
|
// Packages like react-native-pager-view import codegenNativeComponent from
|
||||||
|
// react-native/Libraries/Utilities/codegenNativeComponent, which calls
|
||||||
|
// requireNativeComponent internally. On web (react-native-web), these APIs
|
||||||
|
// don't exist, causing "(0 , _reactNativeWebDistIndex.requireNativeComponent)
|
||||||
|
// is not a function".
|
||||||
|
const webShimPaths = [
|
||||||
|
'react-native/Libraries/Utilities/codegenNativeComponent',
|
||||||
|
'react-native/Libraries/Utilities/codegenNativeCommands',
|
||||||
|
'react-native/Libraries/Types/CodegenTypes',
|
||||||
|
];
|
||||||
|
|
||||||
|
const originalResolveRequest = config.resolver.resolveRequest;
|
||||||
|
const shimDir = path.resolve(__dirname, 'web-shims');
|
||||||
|
|
||||||
|
config.resolver.resolveRequest = (context, moduleName, platform) => {
|
||||||
|
if (platform === 'web' && webShimPaths.some((p) => moduleName.endsWith(p))) {
|
||||||
|
const shimName = moduleName.replace('react-native/Libraries/', '');
|
||||||
|
return {
|
||||||
|
type: 'sourceFile',
|
||||||
|
filePath: path.join(shimDir, 'react-native', 'Libraries', shimName + '.js'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (originalResolveRequest) {
|
||||||
|
return originalResolveRequest(context, moduleName, platform);
|
||||||
|
}
|
||||||
|
return context.resolveRequest(context, moduleName, platform);
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE: enhanceMiddleware is marked as deprecated in Metro's types,
|
// NOTE: enhanceMiddleware is marked as deprecated in Metro's types,
|
||||||
// but there's currently no official alternative for custom dev server headers.
|
// but there's currently no official alternative for custom dev server headers.
|
||||||
// For production, configure COEP/COOP headers on your hosting platform.
|
// For production, configure COEP/COOP headers on your hosting platform.
|
||||||
|
|||||||
17
web-shims/react-native/Libraries/Types/CodegenTypes.js
vendored
Normal file
17
web-shims/react-native/Libraries/Types/CodegenTypes.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const Double = Number;
|
||||||
|
const Int32 = Number;
|
||||||
|
const Float = Number;
|
||||||
|
const WithDefault = (type, defaultValue) => type;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Double,
|
||||||
|
Float,
|
||||||
|
Int32,
|
||||||
|
WithDefault,
|
||||||
|
DirectEventHandler: () => null,
|
||||||
|
BubblingEventHandler: () => null,
|
||||||
|
Stringish: String,
|
||||||
|
ColorValue: null,
|
||||||
|
HandledState: String,
|
||||||
|
WithSpringAnimation: (type) => type,
|
||||||
|
};
|
||||||
15
web-shims/react-native/Libraries/Utilities/codegenNativeCommands.js
vendored
Normal file
15
web-shims/react-native/Libraries/Utilities/codegenNativeCommands.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
function codegenNativeCommands(options) {
|
||||||
|
const commands = {};
|
||||||
|
if (options && options.supportedCommands) {
|
||||||
|
options.supportedCommands.forEach((commandName) => {
|
||||||
|
commands[commandName] = (ref, ...args) => {
|
||||||
|
if (ref && ref.current && typeof ref.current[commandName] === 'function') {
|
||||||
|
ref.current[commandName](...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = codegenNativeCommands;
|
||||||
18
web-shims/react-native/Libraries/Utilities/codegenNativeComponent.js
vendored
Normal file
18
web-shims/react-native/Libraries/Utilities/codegenNativeComponent.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
function codegenNativeComponent(componentName, options) {
|
||||||
|
const componentNameClean = componentName
|
||||||
|
.replace(/^RNC/, '')
|
||||||
|
.replace(/^RNS/, '')
|
||||||
|
.replace(/^RN/, '');
|
||||||
|
|
||||||
|
const NativeComponent = React.forwardRef((props, ref) => {
|
||||||
|
const { children, ...rest } = props;
|
||||||
|
return React.createElement('div', { ...rest, ref, 'data-native-component': componentNameClean }, children);
|
||||||
|
});
|
||||||
|
NativeComponent.displayName = componentName;
|
||||||
|
|
||||||
|
return NativeComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = codegenNativeComponent;
|
||||||
Reference in New Issue
Block a user