Skriv Deres første config plugin
Opret en withMyPlugin-funktion ved hjælp af hjælperne i @expo/config-plugins, tilføj den til plugins-arrayet i app.json, og kør expo prebuild for at verificere det native output.
Skriv Deres første config plugin er en gratis React Native Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i React Native Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. React Native Academy-kurset indeholder 4 lektioner i alt.
Projektopsætning til et konfigurationsplugin
Du kan skrive et konfigurationsplugin som en fil i dit projekt eller som en separat npm-pakke. Til projektspecifikke plugins skal du oprette en mappe med navnet plugins/ i projektets rodmappe og tilføje din plugin-fil der. Referér til den i app.json ved hjælp af en relativ sti. Denne tilgang holder pluginet sammen med appen og kræver ikke et publiceringstrin.
# Project structure
your-expo-app/
plugins/
withCustomPermissions.js <- your plugin
app.json
App.tsx
# app.json reference
{
'expo': {
'plugins': [
['./plugins/withCustomPermissions', { 'reason': 'Scan QR codes' }]
]
}
}Signaturen for funktionen withMyPlugin
Alle konfigurationsplugins er synkrone funktioner, der tager to argumenter: config (det komplette Expo-konfigurationsobjekt) og et valgfrit options-objekt, der sendes fra app.json. Funktionen skal returnere konfigurationsobjektet (i ændret form). Du kæder Expos indbyggede modifikatorhjælpere sammen i denne funktion for at foretage bestemte ændringer i native filer og returnerer derefter resultatet af det sidste modifikatorkald.
// plugins/withCustomPermissions.js
const { withInfoPlist } = require('@expo/config-plugins');
/**
* @param {import('@expo/config-plugins').ExpoConfig} config
* @param {{ reason: string }} options
*/
function withCustomPermissions(config, options = {}) {
const reason = options.reason || 'This app requires camera access.';
return withInfoPlist(config, (iosConfig) => {
iosConfig.modResults['NSCameraUsageDescription'] = reason;
return iosConfig;
});
}
module.exports = withCustomPermissions;Forståelse af modResults
Inde i et mod-callback (som det, der sendes til withInfoPlist) modtager du et konfigurationsobjekt, hvor config.modResults indeholder den parsede native fil som et JavaScript-objekt. For withInfoPlist er det et almindeligt objekt, der afspejler plist-ordbogen. For withAndroidManifest er det et parset XML-dokument. Du ændrer modResults direkte og returnerer konfigurationen — Expo serialiserer den automatisk tilbage til det native filformat.
const { withInfoPlist } = require('@expo/config-plugins');
module.exports = function withAppTrackingPermission(config) {
return withInfoPlist(config, (iosConfig) => {
// modResults is the parsed Info.plist dictionary
const plist = iosConfig.modResults;
// Add multiple keys at once
plist['NSUserTrackingUsageDescription'] =
'We use tracking to improve your ad experience.';
plist['ITSAppUsesNonExemptEncryption'] = false;
return iosConfig;
});
};Ændring af AndroidManifest.xml
Brug withAndroidManifest til at ændre AndroidManifest.xml. modResults er et XML-objekt, der er parset af biblioteket xmldom. Expos AndroidConfig-hjælpere indeholder hjælpefunktioner som addUsesPermission, addMetaDataItemToMainActivity og getMainApplication, der arbejder på denne XML-struktur, så du sjældent behøver at manipulere XML DOM direkte.
const { withAndroidManifest, AndroidConfig } = require('@expo/config-plugins');
const { addUsesPermission } = AndroidConfig.Permissions;
module.exports = function withBluetoothPermissions(config) {
return withAndroidManifest(config, (androidConfig) => {
const manifest = androidConfig.modResults;
// Add multiple permissions
addUsesPermission(manifest, 'android.permission.BLUETOOTH');
addUsesPermission(manifest, 'android.permission.BLUETOOTH_ADMIN');
addUsesPermission(manifest, 'android.permission.BLUETOOTH_SCAN');
return androidConfig;
});
};Test af dit plugin med expo prebuild
Kør npx expo prebuild --clean for at teste dit plugin og undersøge de genererede native filer. Brug --clean til at starte på en frisk. Åbn de genererede filer efter prebuild for at kontrollere, at dine ændringer blev anvendt. Ved plist-ændringer skal du kontrollere ios/YourApp/Info.plist. Ved manifest-ændringer skal du kontrollere android/app/src/main/AndroidManifest.xml. Ret eventuelle problemer i plugin-filen, og kør prebuild igen, indtil outputtet er korrekt.
# Test the plugin
npx expo prebuild --clean --platform ios
# Verify the change in Info.plist
plutil -p ios/MyApp/Info.plist | grep -A1 Camera
# Output:
# "NSCameraUsageDescription" => "Scan QR codes."
# For Android
cat android/app/src/main/AndroidManifest.xml | grep BLUETOOTHTilføjelse af filer til det native projekt
Nogle plugins skal kopiere filer ind i det native projekt — f.eks. en Google Services-JSON-fil eller en tilpasset skrifttype. Brug withDangerousMod til vilkårlige filsystemhandlinger under prebuild. Det er udvejen til ændringer, som ikke dækkes af andre hjælpere. Brug den med omtanke, og dokumentér bivirkningerne tydeligt.
const { withDangerousMod } = require('@expo/config-plugins');
const path = require('path');
const fs = require('fs');
module.exports = function withGoogleServicesJson(config) {
return withDangerousMod(config, [
'android',
async (dangerousConfig) => {
const projectRoot = dangerousConfig.modRequest.projectRoot;
const src = path.join(projectRoot, 'google-services.json');
const dest = path.join(projectRoot, 'android', 'app', 'google-services.json');
if (!fs.existsSync(src)) {
throw new Error('google-services.json not found in project root');
}
fs.copyFileSync(src, dest);
return dangerousConfig;
},
]);
};Adgang til konfigurationsværdier i et plugin
Det config-objekt, der sendes til dit plugin, indeholder den komplette Expo-konfiguration, herunder værdier fra app.json. Du kan læse config.name, config.version, config.ios.bundleIdentifier, config.android.package og alle extra-felter, du har defineret. Det gør det muligt for dit plugin at være datadrevet ud fra appens konfiguration i stedet for at bruge hardkodede værdier.
module.exports = function withAppMetadata(config) {
const appName = config.name;
const bundleId = config.ios?.bundleIdentifier;
const version = config.version;
return withInfoPlist(config, (iosConfig) => {
iosConfig.modResults['CFBundleDisplayName'] = appName;
// Log for debugging during prebuild
console.log(
'[withAppMetadata] Setting display name to:', appName,
'for bundle:', bundleId, 'v' + version
);
return iosConfig;
});
};Ændring af build.gradle med withAppBuildGradle
Hvis du vil ændre Android-appens build.gradle-fil på appniveau, skal du bruge withAppBuildGradle. Egenskaben modResults.contents indeholder filen som en rå streng, og du bruger strengmanipulation eller regex til at indsætte dine ændringer. Denne tilgang er nødvendig for at tilføje Gradle-afhængigheder, pluginerklæringer eller tilpassede buildkonfigurationer, som hjælpefunktionerne på højere niveau ikke dækker.
const { withAppBuildGradle } = require('@expo/config-plugins');
module.exports = function withGooglePlayServicesPlugin(config) {
return withAppBuildGradle(config, (gradleConfig) => {
const contents = gradleConfig.modResults.contents;
// Add google-services plugin if not already present
if (!contents.includes('com.google.gms.google-services')) {
gradleConfig.modResults.contents = contents.replace(
'apply plugin: "com.android.application"',
'apply plugin: "com.android.application"\napply plugin: "com.google.gms.google-services"'
);
}
return gradleConfig;
});
};Ændring af Xcode-projektet med withXcodeProject
Hvis du vil ændre selve Xcode-projektfilen — f.eks. tilføje en buildfase, forbinde et native bibliotek eller tilføje en funktion — skal du bruge withXcodeProject. modResults er et XcodeProject-objekt fra npm-pakken xcode. Dette er den mest komplekse mod og kræver kendskab til Xcode-projektformatet. Foretræk hjælpefunktioner på højere niveau, når de findes.
const { withXcodeProject } = require('@expo/config-plugins');
module.exports = function withRunScript(config) {
return withXcodeProject(config, (xcode) => {
const project = xcode.modResults;
const target = project.getFirstTarget().uuid;
// Add a run script build phase
project.addBuildPhase(
[],
'PBXShellScriptBuildPhase',
'Bundle React Native code and images',
target,
{ shellPath: '/bin/sh', shellScript: 'echo Running custom script' }
);
return xcode;
});
};Entitlements med withEntitlementsPlist
iOS-entitlements er erklæringer af funktioner i en .entitlements-fil, som skal stemme overens med din provisioningprofil. Brug withEntitlementsPlist til at tilføje entitlements som Push Notifications, iCloud, HealthKit eller App Groups. Uden de korrekte entitlements mislykkes funktioner ubemærket ved kørsel på enheden, selv hvis koden ser korrekt ud.
const { withEntitlementsPlist } = require('@expo/config-plugins');
module.exports = function withPushNotifications(config) {
return withEntitlementsPlist(config, (iosConfig) => {
const entitlements = iosConfig.modResults;
// Enable push notifications capability
entitlements['aps-environment'] = 'production';
// App Groups for sharing data with extensions
if (!entitlements['com.apple.security.application-groups']) {
entitlements['com.apple.security.application-groups'] = [];
}
entitlements['com.apple.security.application-groups'].push(
'group.com.yourapp.shared'
);
return iosConfig;
});
};Sammensætning af et komplet plugin
Plugins fra den virkelige verden har ofte brug for at ændre flere native filer på begge platforme. Sammensæt hjælpefunktionerne i rækkefølge, og giv resultatet fra hver funktion videre til den næste. Tilføj tydelig inputvalidering øverst, og log statusmeddelelser, så udviklere kan se, hvad pluginet ændrede under prebuild. Returnér den endelige konfiguration efter alle ændringer.
const {
withInfoPlist,
withAndroidManifest,
withEntitlementsPlist,
AndroidConfig,
} = require('@expo/config-plugins');
module.exports = function withPaymentSDK(config, opts = {}) {
if (!opts.merchantId) {
throw new Error('withPaymentSDK requires a merchantId option.');
}
// iOS
config = withInfoPlist(config, (c) => {
c.modResults['PaymentMerchantId'] = opts.merchantId;
return c;
});
config = withEntitlementsPlist(config, (c) => {
c.modResults['com.apple.developer.in-app-payments'] = [opts.merchantId];
return c;
});
// Android
config = withAndroidManifest(config, (c) => {
AndroidConfig.Permissions.addUsesPermission(
c.modResults, 'android.permission.INTERNET'
);
return c;
});
return config;
};Hurtigt tjek
Test din forståelse af begreberne inden for React Native Mobile Development fra denne lektion.
Opsummering af lektionen
I denne lektion har du lært: hvordan du skriver en konfigurationsplugin-funktion, der tager config og options og returnerer den ændrede konfiguration, hvordan du bruger withInfoPlist, withAndroidManifest, withEntitlementsPlist og withDangerousMod, og hvordan du tester dit plugin med expo prebuild --clean. Du har også set, hvordan du sammensætter flere mods til et komplet plugin på tværs af platforme. Nu skal vi se nærmere på ændring af AndroidManifest og Info.plist.
Lær JavaScript med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 30
- Lektioner
- 120
Ofte stillede spørgsmål
Er lektionen “Skriv Deres første config plugin” gratis?
Ja — alle 3 lektioner i læringssporet React Native Academy, inklusive “Skriv Deres første config plugin”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. React Native Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Skriv Deres første config plugin”?
Opret en withMyPlugin-funktion ved hjælp af hjælperne i @expo/config-plugins, tilføj den til plugins-arrayet i app.json, og kør expo prebuild for at verificere det native output. Du øver dig i React Native Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på React Native Academy?
Der kræves ingen tidligere erfaring. React Native Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Skriv Deres første config plugin”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne React Native Academy-lektion?
Ja. Alle React Native Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Hvad er config plugins, og hvornår bruges de
- Skriv Deres første config plugin
- Ændring af AndroidManifest og Info.plist
- Distribution af config plugins som npm-pakker