Skip to content

Instantly share code, notes, and snippets.

@salman-ibrahim
Last active February 7, 2024 21:52
Show Gist options
  • Save salman-ibrahim/660008506b25f164633bbb393244e013 to your computer and use it in GitHub Desktop.
Save salman-ibrahim/660008506b25f164633bbb393244e013 to your computer and use it in GitHub Desktop.
Appodeal Expo Support Plugins
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">127.0.0.1</domain>
</domain-config>
</network-security-config>
// update root level build.gradle file (module:project)
const { withProjectBuildGradle } = require('@expo/config-plugins');
module.exports = function withAppodealProjectGradle (config) {
return withProjectBuildGradle(config, (config) => {
config.modResults = modifyRootGradle(config.modResults);
return config;
});
}
function modifyRootGradle(gradle) {
const jitpackRepository = "maven { url 'https://www.jitpack.io' }";
const appodealRepository = "maven { url 'https://artifactory.appodeal.com/appodeal' }";
try {
if (gradle.contents.includes(jitpackRepository) && !gradle.contents.includes(appodealRepository)) {
gradle.contents = gradle.contents.replace(
jitpackRepository,
`${jitpackRepository}\n ${appodealRepository}`
);
}
else {
console.error('Failed to modify root Gradle: Jitpack repository not found');
}
} catch (error) {
console.error('Failed to modify root Gradle:', error);
}
return gradle;
}
// update app level build.gradle file (module:app)
const { withAppBuildGradle } = require('@expo/config-plugins');
module.exports = function withAppodealGradle (config) {
return withAppBuildGradle(config, (config) => {
config.modResults = modifyAppGradle(config.modResults);
return config;
});
}
function modifyAppGradle(gradle) {
const dependenciesPattern = /dependencies\s*{([\s\S]*?)}/;
const implementationPattern = /\s*implementation\s*([^\n]*)\n/;
// Find the 'dependencies' block
const dependenciesMatch = gradle.contents.match(dependenciesPattern);
if (dependenciesMatch) {
const dependenciesBlock = dependenciesMatch[1];
// Find the first 'implementation' line within 'dependencies'
const implementationMatch = dependenciesBlock.match(implementationPattern);
if (implementationMatch) {
const existingImplementationLine = implementationMatch[0];
// Insert the new implementation statement below the existing one
const appodealImplementationBlock = `\n implementation("com.appodeal.ads:sdk:3.2.0.+")\n`;
// const multidexImplementationLine = `\n implementation("com.android.support:multidex:1.0.3")\n`;
gradle.contents = gradle.contents.replace(
existingImplementationLine,
existingImplementationLine + appodealImplementationBlock
);
}
}
return gradle;
}
// update AndroidManifest.xml
const { withAndroidManifest } = require('@expo/config-plugins');
module.exports = function withAppodealManifest(config, metaData) {
return withAndroidManifest(config, (config) => {
config.modResults = modifyAndroidManifest(config.modResults, metaData);
return config;
});
}
function modifyAndroidManifest(androidManifest, metaData) {
const application = getApplication(androidManifest);
// Iterate over each key-value pair in manifestConfig.metaData
if (metaData.metaData) {
Object.entries(metaData.metaData).forEach(([key, value]) => {
const existingMetaData = findMetaData(application, key);
if (existingMetaData) {
existingMetaData.$['android:value'] = value;
}
else {
application['meta-data'].push({
$: {
'android:name': key,
'android:value': value,
},
});
}
});
}
return androidManifest;
}
function findMetaData(application, key) {
const metaDatas = application['meta-data'];
if (metaDatas) {
return metaDatas.find((metaData) => metaData.$['android:name'] === key);
}
return null;
}
function getApplication(androidManifest) {
return androidManifest.manifest.application[0];
}
// add network security config xml
const {AndroidConfig, withAndroidManifest } = require('@expo/config-plugins');
const {Paths} = require('@expo/config-plugins/build/android');
const path = require('path');
const fs = require('fs');
const fsPromises = fs.promises;
const { getMainApplicationOrThrow} = AndroidConfig.Manifest
const withTrustLocalCerts = config => {
return withAndroidManifest(config, async config => {
config.modResults = await setCustomConfigAsync(config, config.modResults);
return config;
});
}
async function setCustomConfigAsync(
config,
androidManifest
) {
const src_file_pat = path.join(__dirname, "network_security_config.xml");
const res_file_path = path.join(await Paths.getResourceFolderAsync(config.modRequest.projectRoot),
"xml", "network_security_config.xml");
const res_dir = path.resolve(res_file_path, "..");
if (!fs.existsSync(res_dir)) {
await fsPromises.mkdir(res_dir);
}
try {
await fsPromises.copyFile(src_file_pat, res_file_path);
} catch (e) {
throw e;
}
const mainApplication = getMainApplicationOrThrow(androidManifest);
mainApplication.$["android:networkSecurityConfig"] = "@xml/network_security_config";
return androidManifest;
}
module.exports = withTrustLocalCerts;
@rss14
Copy link

rss14 commented Feb 7, 2024

Feel free to implement this any way you like, but here is how I did it:

  • create a plugins/ directory at project root and add all the files, network_security_config.xml, withAppodealBuildGradle.js, withAppodealGradle.js, withAppodealManifest.js and withTrustLocalCerts.js inside plugins/ directory.
  • update the app.json to use all the plugins as follows:
...
"plugins": [
        ...
        ["./plugins/withAppodealBuildGradle.js"],
        ["./plugins/withAppodealGradle.js"],
        ["./plugins/withTrustLocalCerts.js"],
        [
            "./plugins/withAppodealManifest.js",
            {
                "metaData": {
                    "com.google.android.gms.ads.APPLICATION_ID": "your_admob_app_id",
                    "com.facebook.sdk.ApplicationId": "facebook_app_id",
                    "com.facebook.sdk.ClientToken": "meta_client_token"
                }
            }
        ]
    ],
...

I have kept each plugin for modifying one file only hance, 4 different files. Feel free to combine them into one if you want.

In my case I was doing it for the sake of flexibility so I added params to plugin directly from app.json, if you dont want to supply metaData from app.json feel free to modify withAppodealManifest.js to hard code them directly there.

My Expo Environment

Expo SDK: 48 Flow: Managed Appodeal NPM Package: "react-native-appodeal": "^3.2.1", Node Version: 18.18.0

Note

Your project will stop working in Expo Go after applying these plugins, make sure to run your project in development build afterwards.

Do not omit these values from manifest:

"com.google.android.gms.ads.APPLICATION_ID": "your_admob_app_id",
"com.facebook.sdk.ApplicationId": "facebook_app_id",
"com.facebook.sdk.ClientToken": "meta_client_token"

doing so will cause the app to crash at splash screen. If you want to exclude adMob or Meta SDK then follow the docs here

These configs are written to work with Android only. I would love to see if you can modify them to work with iOS as well.

I didn't find in the documentation how to remove admob and meta ads. I want to use only appodeal, can you help me?

@salman-ibrahim
Copy link
Author

you can visit this link to disable specific ad networks and update the dependencies respectively.

@rss14
Copy link

rss14 commented Feb 7, 2024

you can visit this link to disable specific ad networks and update the dependencies respectively.

Could you adjust the code with this option please? I will be grateful and if it works I will send you a gift. Thank you very much!

@salman-ibrahim
Copy link
Author

I would really love to help you here but due to some workload I won't be of much help. But I tried to figure it out and here is what I came up with, just replace line #29 of withAppodealGradle.js

from:

const appodealImplementationBlock = `\n    implementation("com.appodeal.ads:sdk:3.2.0.+")\n`;

to:

const appodealImplementationBlock = `\n    implementation 'com.appodeal.ads.sdk:core:3.2.0'\n    implementation 'com.appodeal.ads.sdk.networks:bidmachine:3.2.0.0'\n    implementation 'com.appodeal.ads.sdk.networks:bidon:3.2.0.0'\n    implementation 'com.appodeal.ads.sdk.services:sentry_analytics:3.2.0.0'\n     implementation 'com.appodeal.ads.sdk.services:stack_analytics:3.2.0.0'\n    implementation 'com.appodeal.ads.sdk.networks:iab:3.2.0.0'\n`;

This will remove all the mediation adapters from the integration and you will be left with just Appodeal Core Adapters. Once done modify your app.json (if you have implemented already for AdMob and Meta) remove the withAppodealManifest.js plugin i.e., delete these lines:

...
"plugins": [
        ...
        ["./plugins/withAppodealBuildGradle.js"],
        ["./plugins/withAppodealGradle.js"],
        ["./plugins/withTrustLocalCerts.js"],
-       [
-           "./plugins/withAppodealManifest.js",
-           {
-               "metaData": {
-                   "com.google.android.gms.ads.APPLICATION_ID": "your_admob_app_id",
-                   "com.facebook.sdk.ApplicationId": "facebook_app_id",
-                   "com.facebook.sdk.ClientToken": "meta_client_token"
-               }
-           }
-       ]
    ],
...

With that you will be good to go. I hope that helps.

@rss14
Copy link

rss14 commented Feb 7, 2024

I would really love to help you here but due to some workload I won't be of much help. But I tried to figure it out and here is what I came up with, just replace line #29 of withAppodealGradle.js

from:

const appodealImplementationBlock = `\n    implementation("com.appodeal.ads:sdk:3.2.0.+")\n`;

to:

const appodealImplementationBlock = `\n    implementation 'com.appodeal.ads.sdk:core:3.2.0'\n    implementation 'com.appodeal.ads.sdk.networks:bidmachine:3.2.0.0'\n    implementation 'com.appodeal.ads.sdk.networks:bidon:3.2.0.0'\n    implementation 'com.appodeal.ads.sdk.services:sentry_analytics:3.2.0.0'\n     implementation 'com.appodeal.ads.sdk.services:stack_analytics:3.2.0.0'\n    implementation 'com.appodeal.ads.sdk.networks:iab:3.2.0.0'\n`;

This will remove all the mediation adapters from the integration and you will be left with just Appodeal Core Adapters. Once done modify your app.json (if you have implemented already for AdMob and Meta) remove the withAppodealManifest.js plugin i.e., delete these lines:

...
"plugins": [
        ...
        ["./plugins/withAppodealBuildGradle.js"],
        ["./plugins/withAppodealGradle.js"],
        ["./plugins/withTrustLocalCerts.js"],
-       [
-           "./plugins/withAppodealManifest.js",
-           {
-               "metaData": {
-                   "com.google.android.gms.ads.APPLICATION_ID": "your_admob_app_id",
-                   "com.facebook.sdk.ApplicationId": "facebook_app_id",
-                   "com.facebook.sdk.ClientToken": "meta_client_token"
-               }
-           }
-       ]
    ],
...

With that you will be good to go. I hope that helps.

Thanks for the help, but it didn't work.

Could you give me a contact so we can try together and I can pay you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment