React Native Academy · Lektion

Ändra AndroidManifest och Info.plist

Använd withAndroidManifest för att lägga till behörigheter och metadataelement och withInfoPlist för att lägga till nycklar som NSCameraUsageDescription, och testa sedan på båda plattformarna.

Lektion 3 av 413 steg

Ändra AndroidManifest och Info.plist är en gratis lektion i React Native Academy på CoddyKit. Detta är lektion 3 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för React Native Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i React Native Academy innehåller totalt 4 lektioner.

Varför dessa filer är viktiga

AndroidManifest.xml och Info.plist är de centrala konfigurationsfilerna för Android- respektive iOS-appar. De deklarerar behörigheter, funktioner, appkomponenter, URL-scheman, möjligheter och användningsbeskrivningar. Inbyggda bibliotek från tredje part kräver nästan alltid att dessa filer kompletteras. Utan korrekta poster kraschar funktioner, behörigheter nekas och publicering i App Store underkänns vid granskningen.

Anatomin hos AndroidManifest.xml

AndroidManifest.xml har tre huvudavsnitt: uses-permission-element på toppnivå (deklarerar vad appen behöver), application-elementet (inställningar som gäller hela appen, till exempel ikon, tema och säkerhetskopiering) samt activity-, service-, receiver- och provider-element inuti det. Konfigurationsplugin lägger vanligtvis till permissions- och meta-data-element i application- eller activity-elementet.

<!-- Typical AndroidManifest.xml structure -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

  <!-- Permissions at top level -->
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.CAMERA" />

  <application
    android:name=".MainApplication"
    android:label="@string/app_name">

    <!-- meta-data items here -->
    <meta-data android:name="com.google.android.geo.API_KEY"
      android:value="YOUR_KEY" />

    <activity android:name=".MainActivity">
      <!-- intent filters here -->
    </activity>

  </application>
</manifest>

Lägga till permissions i AndroidManifest

Använd AndroidConfig.Permissions.addUsesPermission för att säkert lägga till en permission utan att duplicera den. Hjälpfunktionen kontrollerar om permissionen redan finns innan den läggs till, så det är säkert att köra prebuild flera gånger. Lägg alltid till både dangerous runtime permissions (till exempel CAMERA) och deklarationen uses-feature när appen kräver viss maskinvara, så att appen inte visas i Play Store för inkompatibla enheter.

const { withAndroidManifest, AndroidConfig } = require('@expo/config-plugins');

module.exports = function withCameraAndroid(config) {
  return withAndroidManifest(config, (androidConfig) => {
    const manifest = androidConfig.modResults;

    AndroidConfig.Permissions.addUsesPermission(
      manifest, 'android.permission.CAMERA'
    );
    AndroidConfig.Permissions.addUsesPermission(
      manifest, 'android.permission.READ_MEDIA_IMAGES'
    );

    // Declare hardware requirement
    if (!manifest['uses-feature']) manifest['uses-feature'] = [];
    manifest['uses-feature'].push({
      '$': { 'android:name': 'android.hardware.camera', 'android:required': 'false' }
    });

    return androidConfig;
  });
};

Lägga till meta-data i application-elementet

Många SDK:er (Google Maps, Firebase, Facebook) kräver ett meta-data element inuti taggen application, med en API-nyckel eller ett app-ID. Använd AndroidConfig.Manifest.getMainApplication för att säkert hitta application-elementet och lägg sedan till ett nytt meta-data-objekt i dess array 'meta-data'. Kontrollera alltid att arrayen finns innan du lägger till något, så att du undviker ett null reference-fel.

const { withAndroidManifest, AndroidConfig } = require('@expo/config-plugins');

module.exports = function withGoogleMapsAndroid(config, { apiKey }) {
  return withAndroidManifest(config, (androidConfig) => {
    const manifest = androidConfig.modResults;
    const mainApp = AndroidConfig.Manifest.getMainApplication(manifest);

    if (!mainApp['meta-data']) mainApp['meta-data'] = [];

    // Remove existing key to avoid duplicates
    mainApp['meta-data'] = mainApp['meta-data'].filter(
      (item) => item.$['android:name'] !== 'com.google.android.geo.API_KEY'
    );

    mainApp['meta-data'].push({
      '$': {
        'android:name': 'com.google.android.geo.API_KEY',
        'android:value': apiKey,
      }
    });

    return androidConfig;
  });
};

Intent-filter för deep links

För att registrera ett custom URL scheme eller en Android App Link i Android lägger du till ett intent-filter i huvudaktiviteten. Intent-filtret deklarerar vilka URL-mönster appen hanterar. Konfigurationsplugin kan lägga till dessa programmatiskt genom att hitta MainActivity-elementet och lägga till i dess array för intent-filter.

const { withAndroidManifest, AndroidConfig } = require('@expo/config-plugins');

module.exports = function withDeepLinks(config, { scheme }) {
  return withAndroidManifest(config, (androidConfig) => {
    const manifest = androidConfig.modResults;
    const mainActivity = AndroidConfig.Manifest.getMainActivity(manifest);

    if (!mainActivity['intent-filter']) mainActivity['intent-filter'] = [];

    mainActivity['intent-filter'].push({
      action: [{ '$': { 'android:name': 'android.intent.action.VIEW' } }],
      category: [
        { '$': { 'android:name': 'android.intent.category.DEFAULT' } },
        { '$': { 'android:name': 'android.intent.category.BROWSABLE' } },
      ],
      data: [{ '$': { 'android:scheme': scheme } }],
    });

    return androidConfig;
  });
};

Beskrivningsnycklar för användning i Info.plist

iOS kräver en usage description string i Info.plist för varje känslig permission som appen begär. Om strängen saknas kraschar appen när den anropar requestPermission. Vanliga nycklar är NSCameraUsageDescription, NSLocationWhenInUseUsageDescription, NSMicrophoneUsageDescription, NSPhotoLibraryUsageDescription och NSContactsUsageDescription. Strängen visas i systemets permission-dialog som användaren ser.

const { withInfoPlist } = require('@expo/config-plugins');

module.exports = function withAllPermissions(config, opts = {}) {
  return withInfoPlist(config, (iosConfig) => {
    const plist = iosConfig.modResults;

    plist['NSCameraUsageDescription'] =
      opts.camera || 'Scan QR codes and take profile photos.';
    plist['NSMicrophoneUsageDescription'] =
      opts.microphone || 'Record voice messages.';
    plist['NSLocationWhenInUseUsageDescription'] =
      opts.location || 'Show nearby restaurants.';
    plist['NSPhotoLibraryUsageDescription'] =
      opts.photoLibrary || 'Upload photos from your library.';

    return iosConfig;
  });
};

URL-typer för anpassade scheman i iOS

För att hantera custom URL schemes i iOS (till exempel myapp://) lägger du till en post för CFBundleURLTypes i Info.plist. Varje post har en roll och en array med schemasträngar. Expo konfigurerar automatiskt appens eget schema, men om du behöver ytterligare ett schema (till exempel för en OAuth-omdirigering) måste du lägga till det via ett konfigurationsplugin.

const { withInfoPlist } = require('@expo/config-plugins');

module.exports = function withOAuthScheme(config, { scheme }) {
  return withInfoPlist(config, (iosConfig) => {
    const plist = iosConfig.modResults;

    if (!plist['CFBundleURLTypes']) plist['CFBundleURLTypes'] = [];

    // Avoid duplicate
    const existing = plist['CFBundleURLTypes'].find(
      (t) => t.CFBundleURLName === scheme
    );
    if (!existing) {
      plist['CFBundleURLTypes'].push({
        CFBundleURLName: scheme,
        CFBundleURLSchemes: [scheme],
      });
    }

    return iosConfig;
  });
};

Booleska värden och talvärden i Info.plist

Info.plist stöder flera värdetyper utöver strängar: booleans, numbers, arrays och dictionaries. I objektet JavaScript modResults använder du vanliga JS-booleaner och tal — Expo hanterar korrekt plist-XML-kodning. Om du anger ITSAppUsesNonExemptEncryption till false (ett booleskt värde) slipper de flesta appar frågor om exportefterlevnad i App Store.

const { withInfoPlist } = require('@expo/config-plugins');

module.exports = function withExportCompliance(config) {
  return withInfoPlist(config, (iosConfig) => {
    const plist = iosConfig.modResults;

    // Boolean value
    plist['ITSAppUsesNonExemptEncryption'] = false;

    // Number value
    plist['UIRequiresFullScreen'] = false;

    // Nested dictionary
    plist['NSAppTransportSecurity'] = {
      NSAllowsArbitraryLoads: false,
      NSExceptionDomains: {
        'localhost': { NSExceptionAllowsInsecureHTTPLoads: true }
      }
    };

    return iosConfig;
  });
};

Bakgrundslägen i iOS

iOS-appar som behöver köra kod i bakgrunden måste deklarera UIBackgroundModes i Info.plist. Tillgängliga lägen omfattar audio, location, fetch, remote-notification, processing och voip. Utan rätt deklarerat bakgrundsläge pausar iOS appen när den lämnar förgrunden, och bakgrundsuppgiften avslutas utan synligt fel.

const { withInfoPlist } = require('@expo/config-plugins');

module.exports = function withBackgroundModes(config, { modes }) {
  return withInfoPlist(config, (iosConfig) => {
    const plist = iosConfig.modResults;

    if (!plist['UIBackgroundModes']) plist['UIBackgroundModes'] = [];

    for (const mode of modes) {
      if (!plist['UIBackgroundModes'].includes(mode)) {
        plist['UIBackgroundModes'].push(mode);
      }
    }

    return iosConfig;
  });
};

// app.json usage
// ["./plugins/withBackgroundModes", { "modes": ["audio", "fetch"] }]

Verifiera pluginändringar med plutil och grep

Efter att du har kört expo prebuild ska du alltid verifiera att ändringarna har genomförts korrekt innan du bygger. I macOS använder du plutil -p ios/YourApp/Info.plist för att skriva ut plist-filen i lättläst format. Använd grep för att söka efter specifika strängar i AndroidManifest. Lägg till den här verifieringen i din CI-pipeline, så upptäcks ett trasigt plugin innan byggminuter går till spillo.

# Verify iOS Info.plist
npx expo prebuild --clean --platform ios
plutil -p ios/MyApp/Info.plist | grep NSCamera
# -> "NSCameraUsageDescription" => "Scan QR codes."

# Verify Android manifest permissions
grep 'CAMERA' android/app/src/main/AndroidManifest.xml
# -> <uses-permission android:name="android.permission.CAMERA"/>

# Verify meta-data
grep 'geo.API_KEY' android/app/src/main/AndroidManifest.xml

Idempotens: säkert att köra flera gånger

Ett välskrivet konfigurationsplugin är idempotent — att köra det flera gånger ger samma resultat som att köra det en gång. Skydda varje infogning genom att kontrollera om värdet redan finns innan du lägger till det. Använd filter för att ta bort gamla värden innan du lägger till det nya (ersättningsmönstret), i stället för att lägga till värden blint, vilket skulle skapa dubbletter vid upprepade prebuild-körningar.

// Bad - adds duplicate permissions on every prebuild
manifest['uses-permission'].push({
  '$': { 'android:name': 'android.permission.CAMERA' }
});

// Good - idempotent check first
const hasCameraPermission = manifest['uses-permission']?.some(
  (p) => p.$['android:name'] === 'android.permission.CAMERA'
);
if (!hasCameraPermission) {
  AndroidConfig.Permissions.addUsesPermission(
    manifest, 'android.permission.CAMERA'
  );
}

Snabbtest

Testa dina kunskaper om React Native Mobile Development-koncepten från den här lektionen.

Sammanfattning av lektionen

I den här lektionen har du lärt dig: hur AndroidManifest.xml och Info.plist styr permissions, funktioner och integrationer med operativsystemet, hur du använder withAndroidManifest för att lägga till permissions och meta-data-element samt hur du använder withInfoPlist för att ange användningsbeskrivningar, URL-typer och bakgrundslägen. Du har också lärt dig varför idempotens är viktigt för plugin som körs vid varje prebuild. Nästa steg är att lära dig hur du distribuerar konfigurationsplugin som npm-paket.

Gratis att börja

Lär dig JavaScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
30
Lektioner
120

Vanliga frågor

Är lektionen ”Ändra AndroidManifest och Info.plist” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen React Native Academy, inklusive ”Ändra AndroidManifest och Info.plist”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i React Native Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Ändra AndroidManifest och Info.plist”?

Använd withAndroidManifest för att lägga till behörigheter och metadataelement och withInfoPlist för att lägga till nycklar som NSCameraUsageDescription, och testa sedan på båda plattformarna. Ni övar på React Native Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig React Native Academy?

Du behöver inga förkunskaper. Utbildningen i React Native Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Ändra AndroidManifest och Info.plist”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här React Native Academy-lektionen?

Ja. Varje React Native Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Vad är config plugins och när används de
  2. Skriva ert första config plugin
  3. Ändra AndroidManifest och Info.plist
  4. Distribuera config plugins som npm-paket
← Tillbaka till React Native Academy