Files
wehub-resource-sync 98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:40:49 +08:00

179 lines
5.9 KiB
JavaScript

const { withAndroidManifest } = require('@expo/config-plugins');
/**
* Android hardware feature names that can be marked as optional
*/
const OPTIONAL_HARDWARE_FEATURES = [
// Display features - important for e-ink devices that may not support touch
'android.hardware.touchscreen',
'android.hardware.touchscreen.multitouch',
'android.hardware.touchscreen.multitouch.distinct',
'android.hardware.faketouch',
'android.hardware.screen.portrait',
'android.hardware.screen.landscape',
// Camera features (app uses camera for QR codes but should work without)
'android.hardware.camera',
'android.hardware.camera.autofocus',
'android.hardware.camera.front',
'android.hardware.camera.flash',
'android.hardware.camera.any',
// Communication features - not all e-ink devices have these
'android.hardware.bluetooth',
'android.hardware.bluetooth_le',
'android.hardware.telephony',
'android.hardware.telephony.gsm',
'android.hardware.telephony.cdma',
'android.hardware.wifi',
'android.hardware.wifi.direct',
// Location features - many e-ink readers don't have GPS
'android.hardware.location',
'android.hardware.location.gps',
'android.hardware.location.network',
// Sensors - e-ink devices often lack these sensors
'android.hardware.sensor.accelerometer',
'android.hardware.sensor.barometer',
'android.hardware.sensor.compass',
'android.hardware.sensor.gyroscope',
'android.hardware.sensor.light',
'android.hardware.sensor.proximity',
'android.hardware.sensor.stepcounter',
'android.hardware.sensor.stepdetector',
// Audio - some e-ink devices don't have speakers/microphones
'android.hardware.microphone',
'android.hardware.audio.output',
'android.hardware.audio.low_latency',
'android.hardware.audio.pro',
// Other hardware features
'android.hardware.nfc',
'android.hardware.usb.host',
'android.hardware.usb.accessory',
'android.hardware.vulkan.level',
'android.hardware.vulkan.compute',
'android.hardware.vulkan.version',
'android.hardware.opengles.aep',
'android.hardware.gamepad',
'android.hardware.ram.low',
'android.hardware.ram.normal',
];
/**
* Input configuration attributes for flexible input methods
*/
const INPUT_CONFIGURATION_ATTRIBUTES = [
{ name: 'android:reqFiveWayNav', value: 'false' },
{ name: 'android:reqHardKeyboard', value: 'false' },
{ name: 'android:reqKeyboardType', value: 'undefined' },
{ name: 'android:reqNavigation', value: 'undefined' },
{ name: 'android:reqTouchScreen', value: 'undefined' },
];
/**
* Config plugin to make the app compatible with e-ink readers and other devices
* by marking hardware features as optional instead of required.
*
* This prevents Google Play Store from filtering out the app on devices
* that don't have certain hardware features like cameras, touchscreens, etc.
*/
const withEinkCompatibility = (
config,
options = {}
) => {
const { additionalFeatures = [], verbose = true } = options;
return withAndroidManifest(config, (manifestConfig) => {
const manifest = manifestConfig.modResults.manifest;
// Ensure uses-feature array exists
if (!manifest['uses-feature']) {
manifest['uses-feature'] = [];
}
// Combine default features with any additional features
const allFeatures = [...OPTIONAL_HARDWARE_FEATURES, ...additionalFeatures];
// Add each feature with required="false"
let addedCount = 0;
allFeatures.forEach((featureName) => {
// Check if feature already exists to avoid duplicates
const existingFeature = manifest['uses-feature']?.find(
(f) => f.$?.['android:name'] === featureName
);
if (!existingFeature) {
const newFeature = {
$: {
'android:name': featureName,
'android:required': 'false',
},
};
manifest['uses-feature'].push(newFeature);
addedCount++;
} else if (existingFeature.$?.['android:required'] !== 'false') {
// Update existing feature to not be required
existingFeature.$['android:required'] = 'false';
}
});
// Add support for all screen sizes and densities
// This is important for e-ink devices which may have different screen characteristics
if (!manifest['supports-screens']) {
manifest['supports-screens'] = [];
}
// Clear existing supports-screens and add comprehensive support
const screenSupport = {
$: {
'android:smallScreens': 'true',
'android:normalScreens': 'true',
'android:largeScreens': 'true',
'android:xlargeScreens': 'true',
'android:anyDensity': 'true',
'android:resizeable': 'true',
},
};
manifest['supports-screens'] = [screenSupport];
// Add uses-configuration for different input methods
// This helps with e-ink devices that may use different input methods
if (!manifest['uses-configuration']) {
manifest['uses-configuration'] = [];
}
// Support for devices without touch screens (navigation keys, trackball, etc.)
let configCount = 0;
INPUT_CONFIGURATION_ATTRIBUTES.forEach(({ name, value }) => {
const exists = manifest['uses-configuration']?.find(
(c) => c.$?.[name] !== undefined
);
if (!exists) {
const newConfig = {
$: {
[name]: value,
},
};
manifest['uses-configuration'].push(newConfig);
configCount++;
}
});
// Log plugin activity if verbose mode is enabled
if (verbose) {
console.log('✅ E-ink compatibility plugin applied successfully');
console.log(` Added ${addedCount} optional hardware features`);
console.log(' Added comprehensive screen size support');
console.log(` Added ${configCount} flexible input method configurations`);
}
return manifestConfig;
});
};
module.exports = withEinkCompatibility;