Flutter Native Integration & Platform Configuration Files

#native-integration#platform-channels#android#ios#gradle#plist#podfile#configuration

Answer

Overview

A Flutter project spans two native platforms — Android and iOS — each with its own set of configuration files. Understanding what each file does and when to modify it is essential for native integration, permissions, plugin setup, and release builds.

text
flutter_project/
├── pubspec.yaml                          # Flutter dependencies & assets
├── lib/
│   └── main.dart                         # Flutter entry point
├── android/
│   ├── app/
│   │   ├── src/main/
│   │   │   ├── AndroidManifest.xml       # App permissions & config
│   │   │   └── kotlin/com/example/app/
│   │   │       ├── MainActivity.kt       # Android entry activity
│   │   │       └── MainApplication.kt   # Android application class
│   │   ├── build.gradle.kts             # App-level build config
│   │   └── proguard-rules.pro           # Code shrinking rules
│   ├── settings.gradle.kts              # Project-level Gradle settings
│   ├── gradle.properties                # Gradle JVM & project flags
│   └── local.properties                 # Local SDK path (not committed)
└── ios/
    ├── Runner/
    │   ├── Info.plist                    # iOS app permissions & metadata
    │   ├── AppDelegate.swift             # iOS app lifecycle entry
    │   └── Runner.entitlements           # iOS capabilities
    ├── Podfile                           # iOS CocoaPods dependencies
    ├── Runner.xcworkspace                # ← Always open this in Xcode
    └── Runner.xcodeproj                  # Xcode project structure

Flutter Configuration

1. pubspec.yaml

The central configuration file for every Flutter project. Defines dependencies, assets, fonts, and project metadata.

yaml
name: my_flutter_app
description: A Flutter application
version: 1.0.0+1          # version_name+version_code

environment:
  sdk: '>=3.0.0 <4.0.0'  # Dart SDK constraint

dependencies:
  flutter:
    sdk: flutter
  # Third-party packages
  dio: ^5.3.0
  riverpod: ^2.4.0
  cached_network_image: ^3.3.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0
  build_runner: ^2.4.0

flutter:
  uses-material-design: true

  # Asset declarations — must declare every asset file/folder
  assets:
    - assets/images/
    - assets/icons/logo.png
    - assets/data/config.json

  # Custom fonts
  fonts:
    - family: Poppins
      fonts:
        - asset: assets/fonts/Poppins-Regular.ttf
        - asset: assets/fonts/Poppins-Bold.ttf
          weight: 700

When to modify: Adding packages, declaring assets/fonts, changing app version.


2. main.dart

The Flutter entry point — the first Dart file executed when the app launches.

dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

Future<void> main() async {
  // Must be called before any Flutter framework usage
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize plugins that need async setup
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  // Set preferred device orientations
  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(colorSchemeSeed: Colors.blue),
      home: const HomeScreen(),
    );
  }
}

When to modify: Plugin initialization, app-level configuration, orientation locking, theme setup.


Android Configuration Files

3. AndroidManifest.xml

Located at

text
android/app/src/main/AndroidManifest.xml
. Declares app permissions, activities, services, receivers, and plugin metadata.

xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:label="My App"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:usesCleartextTraffic="false"
        android:enableOnBackInvokedCallback="true">

        <!-- Main Activity -->
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:windowSoftInputMode="adjustResize">
            <meta-data
                android:name="io.flutter.embedding.android.NormalTheme"
                android:resource="@style/NormalTheme" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <!-- Deep link intent filter -->
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="https" android:host="myapp.com" />
            </intent-filter>
        </activity>

        <!-- Firebase / push notifications -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="default_channel" />
    </application>
</manifest>

When to modify: Adding permissions, deep links, push notification config, plugin registration.


4. MainActivity.kt

Located at

text
android/app/src/main/kotlin/.../MainActivity.kt
. The Android entry Activity — Flutter renders inside this.

kotlin
package com.example.myapp

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {

    private val CHANNEL = "com.example.myapp/battery"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        // Register a Platform Channel
        MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            CHANNEL
        ).setMethodCallHandler { call, result ->
            when (call.method) {
                "getBatteryLevel" -> {
                    val level = getBatteryLevel()
                    if (level != -1) result.success(level)
                    else result.error("UNAVAILABLE", "Battery level not available", null)
                }
                else -> result.notImplemented()
            }
        }
    }

    private fun getBatteryLevel(): Int {
        val batteryManager = getSystemService(BATTERY_SERVICE) as android.os.BatteryManager
        return batteryManager.getIntProperty(android.os.BatteryManager.BATTERY_PROPERTY_CAPACITY)
    }
}

When to modify: Registering platform channels, handling Android-specific intents, overriding activity lifecycle.


5. MainApplication.kt

Located alongside

text
MainActivity.kt
. The Android Application class — runs before any Activity, used for app-wide initialization.

kotlin
package com.example.myapp

import io.flutter.app.FlutterApplication

// For older Flutter projects — newer ones use ${applicationName} in manifest
class MainApplication : FlutterApplication() {

    override fun onCreate() {
        super.onCreate()
        // App-wide initializations that must run before any Activity
        // e.g. crash reporting, dependency injection
    }
}

Modern Flutter projects use

text
${applicationName}
in
text
AndroidManifest.xml
and don't require a custom
text
MainApplication
unless you need app-level hooks.

When to modify: App-wide Android initialization (crash reporters, DI frameworks, WorkManager).


6. android/app/build.gradle.kts

The app-level build script — controls SDK versions, app ID, versioning, signing, and dependencies.

kotlin
plugins {
    id("com.android.application")
    id("kotlin-android")
    id("dev.flutter.flutter-gradle-plugin")
    id("com.google.gms.google-services") // Firebase
}

android {
    namespace = "com.example.myapp"
    compileSdk = flutter.compileSdkVersion

    defaultConfig {
        applicationId = "com.example.myapp"
        minSdk = 21              // Minimum Android version (Android 5.0)
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName
        multiDexEnabled = true   // Required for large apps
    }

    // Release signing configuration
    signingConfigs {
        create("release") {
            keyAlias = System.getenv("KEY_ALIAS")
            keyPassword = System.getenv("KEY_PASSWORD")
            storeFile = file(System.getenv("KEYSTORE_PATH") ?: "keystore.jks")
            storePassword = System.getenv("STORE_PASSWORD")
        }
    }

    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
            isMinifyEnabled = true           // Enable code shrinking
            isShrinkResources = true         // Remove unused resources
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        debug {
            isDebuggable = true
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = "17"
    }
}

flutter {
    source = "../.."
}

dependencies {
    implementation(platform("com.google.firebase:firebase-bom:32.7.0"))
    implementation("com.google.firebase:firebase-analytics")
    implementation("androidx.multidex:multidex:2.0.1")
}

When to modify: Changing minSdk, adding signing config, enabling multidex, adding native Android dependencies.


7. settings.gradle.kts

The project-level Gradle settings — defines which modules are included and configures plugin repositories.

kotlin
pluginManagement {
    val flutterSdkPath = run {
        val properties = java.util.Properties()
        file("local.properties").inputStream().use { properties.load(it) }
        val flutterSdkPath = properties.getProperty("flutter.sdk")
        require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
        flutterSdkPath
    }

    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

plugins {
    id("dev.flutter.flutter-plugin-loader") version "1.0.0"
    id("com.android.application") version "8.3.0" apply false
    id("org.jetbrains.kotlin.android") version "1.9.22" apply false
    id("com.google.gms.google-services") version "4.4.1" apply false
}

include(":app")

When to modify: Adding Gradle plugins (Firebase, Crashlytics), changing Kotlin/AGP versions.


8. gradle.properties

Project-wide Gradle configuration flags — controls JVM memory, AndroidX, and build optimizations.

properties
# JVM heap size — increase if Gradle runs out of memory
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError

# Enable Gradle daemon for faster builds
org.gradle.daemon=true

# Enable parallel project execution
org.gradle.parallel=true

# Enable Gradle build cache
org.gradle.caching=true

# AndroidX migration (mandatory for modern Flutter)
android.useAndroidX=true
android.enableJetifier=true

# R8 full mode for better shrinking
android.enableR8.fullMode=false

# Kotlin code style
kotlin.code.style=official

When to modify: Increasing JVM memory (build OOM errors), enabling AndroidX, tuning build performance.


9. local.properties

Machine-specific configuration — stores local SDK paths. Never commit to Git (already in

text
.gitignore
).

properties
# Android SDK location on this machine
sdk.dir=/Users/venkatraman/Library/Android/sdk

# Flutter SDK location
flutter.sdk=/Users/venkatraman/fvm/versions/3.19.0

# App version (read by build.gradle.kts via flutter.versionName/Code)
flutter.versionName=1.0.0
flutter.versionCode=1
flutter.buildMode=release

When to modify: Typically auto-generated. Modify manually if SDK path changes or using FVM.


10. proguard-rules.pro

Android code shrinking rules — tells R8/ProGuard what NOT to remove when

text
isMinifyEnabled = true
in release builds.

pro
# Keep Flutter engine classes
-keep class io.flutter.** { *; }
-keep class io.flutter.embedding.** { *; }

# Keep plugin classes (add rules for each plugin you use)
-keep class com.google.firebase.** { *; }
-keep class com.google.android.gms.** { *; }

# Keep model classes used with Gson/JSON serialization
-keep class com.example.myapp.models.** { *; }
-keepclassmembers class com.example.myapp.models.** { *; }

# Keep Kotlin Serialization
-keepattributes *Annotation*
-keepclassmembers class kotlinx.serialization.json.** { *** *; }

# Prevent obfuscation of class names used with reflection
-keepnames class * implements java.io.Serializable

# Keep enums
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }

# Suppress warnings for missing classes (optional)
-dontwarn org.bouncycastle.**
-dontwarn com.sun.jna.**

When to modify: When release builds crash with

text
ClassNotFoundException
or plugin issues — add
text
-keep
rules for affected classes.


iOS Configuration Files

11. Info.plist

Located at

text
ios/Runner/Info.plist
. The iOS app manifest — declares permissions, URL schemes, display name, and capabilities.

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
    <!-- App display name -->
    <key>CFBundleDisplayName</key>
    <string>My App</string>

    <!-- Bundle ID -->
    <key>CFBundleIdentifier</key>
    <string>com.example.myapp</string>

    <!-- Version -->
    <key>CFBundleShortVersionString</key>
    <string>$(FLUTTER_BUILD_NAME)</string>
    <key>CFBundleVersion</key>
    <string>$(FLUTTER_BUILD_NUMBER)</string>

    <!-- Privacy usage descriptions — required for App Store -->
    <key>NSCameraUsageDescription</key>
    <string>This app needs camera access to take photos.</string>

    <key>NSPhotoLibraryUsageDescription</key>
    <string>This app needs photo library access to select images.</string>

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>This app uses your location to show nearby places.</string>

    <key>NSMicrophoneUsageDescription</key>
    <string>This app uses the microphone for voice recording.</string>

    <key>NSFaceIDUsageDescription</key>
    <string>This app uses Face ID for secure authentication.</string>

    <!-- Deep link URL scheme -->
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myapp</string>
            </array>
        </dict>
    </array>

    <!-- Allow HTTP for specific domains (disable ATS) -->
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <false/>
        <key>NSExceptionDomains</key>
        <dict>
            <key>api.myapp.com</key>
            <dict>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>

    <!-- Background modes -->
    <key>UIBackgroundModes</key>
    <array>
        <string>fetch</string>
        <string>remote-notification</string>
    </array>
</dict>
</plist>

When to modify: Adding permissions, URL schemes for deep links, background modes, App Transport Security exceptions.


12. AppDelegate.swift

Located at

text
ios/Runner/AppDelegate.swift
. The iOS application lifecycle entry point — registers Flutter engine and handles app events.

swift
import UIKit
import Flutter
import Firebase

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        // Configure Firebase
        FirebaseApp.configure()

        // Register Flutter plugins (auto-registered in modern Flutter)
        GeneratedPluginRegistrant.register(with: self)

        // Register a Platform Channel
        let controller = window?.rootViewController as! FlutterViewController
        let batteryChannel = FlutterMethodChannel(
            name: "com.example.myapp/battery",
            binaryMessenger: controller.binaryMessenger
        )

        batteryChannel.setMethodCallHandler { call, result in
            guard call.method == "getBatteryLevel" else {
                result(FlutterMethodNotImplemented)
                return
            }
            self.receiveBatteryLevel(result: result)
        }

        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    // Handle push notification registration
    override func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        Messaging.messaging().apnsToken = deviceToken
        super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
    }

    // Handle deep links
    override func application(
        _ app: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey: Any] = [:]
    ) -> Bool {
        return super.application(app, open: url, options: options)
    }

    private func receiveBatteryLevel(result: FlutterResult) {
        UIDevice.current.isBatteryMonitoringEnabled = true
        if UIDevice.current.batteryState == .unknown {
            result(FlutterError(code: "UNAVAILABLE", message: "Battery info unavailable", details: nil))
        } else {
            result(Int(UIDevice.current.batteryLevel * 100))
        }
    }
}

When to modify: Firebase setup, platform channels, push notifications, deep link handling, iOS lifecycle hooks.


13. Runner.entitlements

Located at

text
ios/Runner/Runner.entitlements
. Declares iOS capabilities — required for features like push notifications, iCloud, Sign in with Apple, etc.

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
    <!-- Push Notifications (APNs) -->
    <key>aps-environment</key>
    <string>development</string>   <!-- Use 'production' for App Store -->

    <!-- iCloud -->
    <key>com.apple.developer.icloud-container-identifiers</key>
    <array>
        <string>iCloud.com.example.myapp</string>
    </array>

    <!-- Sign in with Apple -->
    <key>com.apple.developer.applesignin</key>
    <array>
        <string>Default</string>
    </array>

    <!-- HealthKit -->
    <key>com.apple.developer.healthkit</key>
    <true/>

    <!-- Associated Domains (Universal Links / deep links) -->
    <key>com.apple.developer.associated-domains</key>
    <array>
        <string>applinks:myapp.com</string>
        <string>webcredentials:myapp.com</string>
    </array>
</dict>
</plist>

When to modify: Enabling push notifications, Universal Links, Sign in with Apple, iCloud, HealthKit, or any capability that needs Apple's entitlement system.


14. Podfile

Located at

text
ios/Podfile
. The iOS CocoaPods dependency file — manages native iOS libraries required by Flutter plugins.

ruby
# Minimum iOS version — must match flutter plugin requirements
platform :ios, '13.0'

# CocoaPods analytics opt-out
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(
    File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__
  )
  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

  # Additional native pods (if needed directly)
  # pod 'GoogleMaps', '~> 8.0'

  target 'RunnerTests' do
    inherit! :search_paths
  end
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    # Fix deployment target warnings
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
    end
  end
end

Commands:

bash
cd ios && pod install    # Install/update pods
cd ios && pod update     # Update all pods to latest
cd ios && pod deintegrate && pod install  # Clean reinstall

When to modify: Changing minimum iOS version, fixing pod conflicts, adding native iOS-only libraries.


15. Runner.xcworkspace

Located at

text
ios/Runner.xcworkspace
. The Xcode workspace that includes both the Flutter Runner project and CocoaPods.

Always open

text
Runner.xcworkspace
, never
text
Runner.xcodeproj
directly.
Opening
text
.xcodeproj
alone misses CocoaPods dependencies and will fail to build.

bash
# Open correct file
open ios/Runner.xcworkspace

# Or via Flutter
flutter build ios          # Build for device
flutter run --release      # Run release on connected device

Contains:

  • text
    Runner.xcodeproj
    — the actual Xcode project
  • text
    Pods.xcodeproj
    — auto-generated by CocoaPods

When to modify: Indirectly — through Xcode for signing, capabilities, build settings.


16. Runner.xcodeproj

Located at

text
ios/Runner.xcodeproj
. The raw Xcode project — defines build targets, schemes, file references, and build phases.

Key files inside:

FilePurpose
text
project.pbxproj
Machine-generated project structure (avoid manual edits)
text
xcshareddata/xcschemes/
Build schemes (Debug, Release, Profile)

Common Xcode settings configured here:

  • Bundle Identifier
  • Signing Team & Provisioning Profile
  • Build Number / Version
  • Deployment Target
  • Capabilities (automatically mirrors
    text
    Runner.entitlements
    )

When to modify: Via Xcode UI — for signing, capabilities, adding files to the build target.


17. Platform Channels

The mechanism for Flutter ↔ Native communication. Three channel types:

Channel TypeDirectionUse Case
text
MethodChannel
Bidirectional (request-response)Single calls (battery level, file picker)
text
EventChannel
Native → Flutter (stream)Continuous data (sensors, connectivity)
text
BasicMessageChannel
Bidirectional (messages)Custom codec communication

MethodChannel Example

Flutter side (Dart):

dart
import 'package:flutter/services.dart';

class BatteryService {
  static const _channel = MethodChannel('com.example.myapp/battery');

  static Future<int> getBatteryLevel() async {
    try {
      final int level = await _channel.invokeMethod('getBatteryLevel');
      return level;
    } on PlatformException catch (e) {
      throw Exception('Failed to get battery level: ${e.message}');
    }
  }
}

// Usage in widget
final level = await BatteryService.getBatteryLevel();

Android side (Kotlin) — in MainActivity.kt:

kotlin
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.myapp/battery")
    .setMethodCallHandler { call, result ->
        if (call.method == "getBatteryLevel") {
            result.success(getBatteryLevel())
        } else {
            result.notImplemented()
        }
    }

iOS side (Swift) — in AppDelegate.swift:

swift
FlutterMethodChannel(name: "com.example.myapp/battery", binaryMessenger: controller.binaryMessenger)
    .setMethodCallHandler { call, result in
        if call.method == "getBatteryLevel" {
            result(Int(UIDevice.current.batteryLevel * 100))
        } else {
            result(FlutterMethodNotImplemented)
        }
    }

EventChannel Example — Continuous Stream

dart
// Flutter — listen to native stream
const _channel = EventChannel('com.example.myapp/connectivity');

Stream<bool> get connectivityStream =>
    _channel.receiveBroadcastStream().map((event) => event as bool);
kotlin
// Android — send events to Flutter
EventChannel(messenger, "com.example.myapp/connectivity")
    .setStreamHandler(object : EventChannel.StreamHandler {
        override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
            // Send connectivity updates
            events.success(isConnected)
        }
        override fun onCancel(arguments: Any?) {}
    })

Quick Reference Table

FilePlatformPurposeModify When
text
pubspec.yaml
FlutterDependencies, assets, fontsAdding packages or assets
text
main.dart
FlutterApp entry pointPlugin init, theme, orientation
text
AndroidManifest.xml
AndroidPermissions, activitiesAdding permissions, deep links
text
MainActivity.kt
AndroidFlutter activity + channelsPlatform channels, intents
text
MainApplication.kt
AndroidApp-level Android initApp-wide native initialization
text
build.gradle.kts
AndroidSDK versions, signing, depsminSdk, signing, native deps
text
settings.gradle.kts
AndroidGradle modules & pluginsAdding Gradle plugins
text
gradle.properties
AndroidJVM memory, AndroidX flagsOOM errors, build tuning
text
local.properties
AndroidLocal SDK pathsSDK path changes, FVM
text
proguard-rules.pro
AndroidCode shrinking rulesRelease crashes, R8 issues
text
Info.plist
iOSPermissions, URL schemesAdding permissions, deep links
text
AppDelegate.swift
iOSiOS lifecycle + channelsFirebase, push, channels
text
Runner.entitlements
iOSiOS capabilitiesPush notif, Universal Links
text
Podfile
iOSCocoaPods dependenciesiOS version, pod conflicts
text
Runner.xcworkspace
iOSOpen this in XcodeAlways (not .xcodeproj)
text
Runner.xcodeproj
iOSXcode build configSigning, capabilities
Platform ChannelsBothFlutter ↔ Native bridgeNative API access