Peakiq Blog
20 December 2025

Expo config plugins allow you to extend and customize the native behavior of your Expo app. Here, we will create a plugin that modifies various aspects of the Android project configuration, including the AndroidManifest.xml, Gradle properties, and MainApplication.java file.
First, ensure you have the necessary imports from @expo/config-plugins:
const { withAndroidManifest, withGradleProperties, withProjectBuildGradle, withAppBuildGradle, withMainApplication } = require("@expo/config-plugins");
We will define various configuration changes that our plugin will apply:
const new_Gradle_Properties = [
{ type: 'property', key: 'AsyncStorage_db_size_in_MB', value: '2048' },
{ type: 'property', key: 'android.disableAutomaticComponentCreation', value: 'true' },
{ type: 'property', key: 'hermesEnabled', value: 'false' }
];
const new_Activities = [
{ $: { "android:name": 'com.ahmedadeltito.photoeditor.PhotoEditorActivity' } },
{ $: { "android:name": 'com.yalantis.ucrop.UCropActivity' } }
];
const new_intentData = [
{ $: { "android:mimeType": "*/*" } }
];
We will modify the MainApplication.java file to include necessary imports and update the onCreate method to change the CursorWindow size:
const ModifyMainApplication = withMainApplication(config, async config => {
let { contents } = config.modResults;
if (!contents.includes('import static com.facebook.react.views.textinput.ReactEditText.DEBUG_MODE;')) {
const packageIndex = contents.indexOf('package ');
const packageEndIndex = contents.indexOf(';', packageIndex) + 1;
contents = [
contents.slice(0, packageEndIndex),
`\nimport static com.facebook.react.views.textinput.ReactEditText.DEBUG_MODE;
import android.database.CursorWindow;
import java.lang.reflect.Field;\n`,
contents.slice(packageEndIndex)
].join('');
}
const onCreateMethodMatch = 'super.onCreate();';
const tryCatchBlock = `
try {
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
field.setAccessible(true);
field.set(null, 100 * 1024 * 1024); // 100MB
} catch (Exception e) {
if (DEBUG_MODE) {
e.printStackTrace();
}
}
`;
if (contents.includes(onCreateMethodMatch) && !contents.includes(tryCatchBlock.trim())) {
contents = contents.replace(
onCreateMethodMatch,
`${onCreateMethodMatch}${tryCatchBlock}`
);
}
config.modResults.contents = contents;
return config;
});
We will add new activities and intent filters to the AndroidManifest.xml:
const AddActivityMain_fest = withAndroidManifest(config, async config => {
const androidManifest = config.modResults.manifest;
const mainApplication = androidManifest.application[0];
mainApplication.$['android:hardwareAccelerated'] = 'true';
mainApplication.$['android:largeHeap'] = 'true';
const currentActivities = mainApplication.activity;
new_Activities.map(activity => {
const foundActivity = currentActivities.find(anActivity => anActivity.$['android:name'] === activity.$['android:name']);
if (!foundActivity)
currentActivities.push(activity);
});
const currIntent = androidManifest.queries[0]?.intent[0].data;
new_intentData.map(intentData => {
const foundIntentData = currIntent.find(anIntendData => anIntendData.$['android:mimeType'] === intentData.$['android:mimeType']);
if (!foundIntentData)
currIntent.push(intentData);
});
return config;
});
We will set the new Gradle properties:
const SetGradleProperties = withGradleProperties(config, config => {
new_Gradle_Properties.map(gradleProperty => {
const foundProperty = config.modResults.find(prop => prop.key === gradleProperty.key);
if (foundProperty) {
foundProperty.value = gradleProperty.value;
} else {
config.modResults.push(gradleProperty);
}
});
return config;
});
We will modify the project and app build gradle files:
const SetAppBuildGradleProperties = withProjectBuildGradle(config, config => {
config.modResults.contents += `
subprojects { subproject ->
if(project['name'] == 'react-native-reanimated'){
project.configurations { compile { } }
}
}`;
return config;
});
const SetAppBuildGradle = withAppBuildGradle(config, config => {
config.modResults.contents += `
android { defaultConfig {
manifestPlaceholders = [appAuthRedirectScheme: 'gopak360']
}}`;
return config;
});
Finally, we export the plugin by combining all the modifications:
module.exports = function AndroidPlugin(config) {
return Object.assign(
SetGradleProperties,
AddActivityMain_fest,
SetAppBuildGradleProperties,
SetAppBuildGradle,
ModifyMainApplication
);
};
By following the steps outlined above, you can create a custom Android config plugin for Expo to manage and modify your Android project's configuration efficiently. This approach helps keep your project maintainable and flexible, allowing for easy updates and modifications. For more details and advanced usage, refer to the Expo documentation.