React Native开发中常见的 Android 原生文件

607 阅读9分钟

在React Native 开发Android时,理解和正确配置核心文件是构建高效、稳定应用的关键。本文将深入探讨三个重要方面:配置文件、应用结构和资源管理。我们将详细介绍AndroidManifest.xml、build.gradle文件的作用和配置方法,解析MainApplication类的结构和功能,以及探讨strings.xml在资源管理中的重要性。无论您是初学者还是有经验的开发者,本文都将为您提供全面而实用的指南,帮助您更好地掌握React Native Android开发的核心要素。

配置

AndroidManifest.xml

image.png AndroidManifest.xml 文件是 Android 应用程序的核心配置文件,它在 React Native 开发中同样扮演着重要角色。这个文件位于 \android\app\src\main\AndroidManifest.xml,包含了应用程序的基本信息和配置。让我为详细介绍它的作用和内容:

应用程序信息

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    android:versionCode="1"
    android:versionName="1.0">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name">
        <!-- 其他配置 -->
    </application>
</manifest>

这里,package 定义了包名,versionCodeversionName 分别设置版本号和版本名称,icon 设置应用图标,label 设置应用名称。

权限声明

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- 其他权限 -->
</manifest>

这些 <uses-permission> 标签声明了应用需要的各种权限。

组件声明

<application>
    <activity android:name=".MainActivity">
        <!-- 配置 -->
    </activity>

    <service android:name=".MyService" />

    <receiver android:name=".MyReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
</application>

这里声明了一个活动(Activity)、一个服务(Service)和一个广播接收器(Broadcast Receiver)。

应用程序入口点

<application>
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

这个配置指定了 MainActivity 作为应用的主入口点。

硬件和软件要求

<manifest>
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    <uses-feature android:name="android.hardware.bluetooth" android:required="true" />
    
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
</manifest>

这里声明了对相机和蓝牙的需求,以及应用支持的最低和目标 SDK 版本。

屏幕配置

<manifest>
    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    
    <application
        android:resizeableActivity="true"
        android:screenOrientation="portrait">
        <!-- 活动配置 -->
    </application>
</manifest>

这个配置指定了支持的屏幕尺寸和应用的屏幕方向。

综合示例

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />

    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:resizeableActivity="true">

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".MyService" />

        <receiver android:name=".MyReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

这个综合示例包含了所有上述配置。在实际使用时,我们需要根据自己的应用需求来调整这些配置。

android/build.gradle

这个文件是项目级别的构建配置文件,用于配置整个Android项目的构建设置,我们通常不会改动它,除非产品迭代时不再考虑低版本的系统,需要改动该文件,例如将minSdkVersion改为24。

主要作用:

  • 定义项目级别的构建配置
  • 设置构建脚本的依赖
  • 配置所有模块共用的属性
  • 定义项目范围内的变量

我们需要修改maven的源,来提高下载速度,示例如下:

buildscript {
    ext {
        buildToolsVersion = "34.0.0"
        minSdkVersion = 24
        compileSdkVersion = 34
        targetSdkVersion = 34
        ndkVersion = "26.1.10909125"
        kotlinVersion = "1.9.22"
    }
    repositories {
        maven{url 'https://maven.aliyun.com/nexus/content/groups/public/'}
        google()
        // mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle")
        classpath("com.facebook.react:react-native-gradle-plugin")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
    }
}

apply plugin: "com.facebook.react.rootproject"

这个文件定义了整个项目的构建工具版本、SDK版本、依赖仓库等信息,这些设置会被所有模块共享。

android/app/build.gradle

android/app/build.gradle 文件是应用模块的构建配置文件,通常我们会经常改动这个 build.gradle 文件

主要作用:

定义应用的构建类型(debug、release等)

构建类型定义了不同的构建配置,最常见的是 debug 和 release。

示例代码:

android {
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}

这里定义了 debug 和 release 两种构建类型,它们有不同的混淆设置和签名配置。

配置应用的版本信息

版本信息包括 versionCode(内部版本号)和 versionName(用户可见的版本号)。

示例代码:

android {
    defaultConfig {
        versionCode 1
        versionName "1.0.0"
    }
}

versionCode 通常是一个整数,每次发布新版本时递增。versionName 是一个字符串,表示用户可见的版本号。

设置应用的依赖项

依赖项定义了应用需要使用的库和模块。

示例代码:

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "com.facebook.react:react-native:+"
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
    implementation project(':react-native-vector-icons')
}

这里添加了 React Native 核心库、AndroidX SwipeRefreshLayout 库和一个第三方 React Native 模块。

配置签名信息

签名信息用于在发布应用时进行身份验证。

示例代码:

android {
    signingConfigs {
        release {
            storeFile file("my-release-key.keystore")
            storePassword "password"
            keyAlias "my-key-alias"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

这里定义了一个 release 签名配置,并在 release 构建类型中使用它。

设置NDK配置

NDK(Native Development Kit)配置用于原生代码开发。

示例代码:

android {
    ndkVersion "21.4.7075529"
    
    defaultConfig {
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }
    }
}

这里设置了 NDK 版本,并指定了支持的 ABI(应用程序二进制接口)。

配置打包选项

打包选项可以自定义 APK 的生成过程。

示例代码:

android {
    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/*.kotlin_module'
    }
}

这个配置排除了一些可能导致构建冲突的文件。

综合示例

apply plugin: "com.android.application"

android {
    compileSdkVersion rootProject.ext.compileSdkVersion

    defaultConfig {
        applicationId "com.example.myapp"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0.0"
        
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }
    }

    signingConfigs {
        release {
            storeFile file("my-release-key.keystore")
            storePassword "password"
            keyAlias "my-key-alias"
            keyPassword "password"
        }
    }

    buildTypes {
        debug {
            minifyEnabled false
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            signingConfig signingConfigs.release
        }
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "com.facebook.react:react-native:+"
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
}

这个综合示例包含了我们讨论的所有主要部分。通过理解和正确配置这些部分,我们可以更好地控制 React Native Android 应用的构建过程和最终产品。

应用

Application

让我们逐一探讨 MainApplication.kt 的主要作用:

继承 Application 类

作用:创建一个自定义的 Application 类,用于全局初始化和配置。

示例:

class MainApplication : Application(), ReactApplication {
    // ...
}

实现 ReactApplication 接口

作用:表明这是一个 React Native 应用,并提供必要的方法。

示例:

class MainApplication : Application(), ReactApplication {
    override fun getReactNativeHost(): ReactNativeHost {
        return reactNativeHost
    }
    // ...
}
  1. 创建和配置 ReactNativeHost

作用:设置 React Native 环境,包括是否使用开发者服务器、是否启用 Hermes 引擎等。

示例:

private val reactNativeHost = object : ReactNativeHost(this) {
    override fun getUseDeveloperSupport(): Boolean {
        return BuildConfig.DEBUG
    }

    override fun getPackages(): List<ReactPackage> {
        return PackageList(this).packages
    }

    override fun getJSMainModuleName(): String {
        return "index"
    }

    override fun getJSBundleFile(): String? {
        return CodePush.getJSBundleFile()
    }

    override fun getUseDeveloperSupport(): Boolean {
        return BuildConfig.DEBUG
    }

    override fun isHermesEnabled(): Boolean {
        return BuildConfig.IS_HERMES_ENABLED
    }
}
  1. 初始化第三方库

作用:在应用启动时初始化需要全局配置的第三方库。

示例:

override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, false)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
        // 如果启用了新架构,初始化 Fabric
        initializeFlipper(this, reactNativeHost.reactInstanceManager)
    }
    // 初始化其他第三方库
    initializeThirdPartyLibraries()
}

private fun initializeThirdPartyLibraries() {
    // 例如,初始化 Firebase
    FirebaseApp.initializeApp(this)
    // 初始化崩溃报告工具
    Crashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
}
  1. 配置调试工具(如 Flipper)

作用:在调试模式下初始化和配置调试工具。

示例:

private fun initializeFlipper(context: Context, reactInstanceManager: ReactInstanceManager) {
    if (BuildConfig.DEBUG) {
        try {
            val aClass = Class.forName("com.pixiu_react_native_template.ReactNativeFlipper")
            aClass.getMethod("initializeFlipper", Context::class.java, ReactInstanceManager::class.java)
                .invoke(null, context, reactInstanceManager)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        } catch (e: NoSuchMethodException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            e.printStackTrace()
        }
    }
}
  1. 重写 getPackages 方法

作用:提供 React Native 使用的原生模块列表。

示例:

override fun getPackages(): List<ReactPackage> {
    val packages = PackageList(this).packages
    // 可以在这里手动添加包
    packages.add(MyCustomPackage())
    return packages
}
  1. 配置 CodePush(如果使用)

作用:设置 CodePush 以支持热更新。

示例:

override fun getJSBundleFile(): String? {
    return CodePush.getJSBundleFile()
}

完整的 MainApplication.kt 示例:

package com.pixiu_react_native_template

import android.app.Application
import android.content.Context
import com.facebook.react.*
import com.facebook.soloader.SoLoader
import com.microsoft.codepush.react.CodePush

class MainApplication : Application(), ReactApplication {

    private val reactNativeHost = object : ReactNativeHost(this) {
        override fun getUseDeveloperSupport(): Boolean {
            return BuildConfig.DEBUG
        }

        override fun getPackages(): List<ReactPackage> {
            return PackageList(this).packages.apply {
                // 可以在这里添加自定义包
                // add(MyCustomPackage())
            }
        }

        override fun getJSMainModuleName(): String {
            return "index"
        }

        override fun getJSBundleFile(): String? {
            return CodePush.getJSBundleFile()
        }

        override fun isHermesEnabled(): Boolean {
            return BuildConfig.IS_HERMES_ENABLED
        }
    }

    override fun getReactNativeHost(): ReactNativeHost {
        return reactNativeHost
    }

    override fun onCreate() {
        super.onCreate()
        SoLoader.init(this, false)
        if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
            initializeFlipper(this, reactNativeHost.reactInstanceManager)
        }
        initializeThirdPartyLibraries()
    }

    private fun initializeThirdPartyLibraries() {
        // 初始化第三方库
    }

    private fun initializeFlipper(context: Context, reactInstanceManager: ReactInstanceManager) {
        if (BuildConfig.DEBUG) {
            try {
                val aClass = Class.forName("com.pixiu_react_native_template.ReactNativeFlipper")
                aClass.getMethod("initializeFlipper", Context::class.java, ReactInstanceManager::class.java)
                    .invoke(null, context, reactInstanceManager)
            } catch (e: ClassNotFoundException) {
                e.printStackTrace()
            } catch (e: NoSuchMethodException) {
                e.printStackTrace()
            } catch (e: IllegalAccessException) {
                e.printStackTrace()
            } catch (e: InvocationTargetException) {
                e.printStackTrace()
            }
        }
    }
}

这个文件是 React Native Android 应用的核心配置文件,它负责设置 React Native 环境、管理原生模块、初始化第三方库,以及配置调试工具。正确配置这个文件对于应用的正常运行至关重要。

String

android/app/src/main/res/values/strings.xml 文件的作用及其示例。这个文件是 Android 资源文件系统的一部分,主要用于存储应用中使用的字符串资源。

主要作用:

集中管理应用中的文本字符串

作用:将应用中使用的文本字符串集中在一个地方管理,便于维护和更新。

示例:

<resources>
    <string name="app_name">My React Native App</string>
    <string name="welcome_message">Welcome to my app!</string>
    <string name="login_button">Log In</string>
    <string name="signup_button">Sign Up</string>
</resources>

支持多语言本地化

作用:通过在不同语言文件夹中创建相应的 strings.xml 文件,可以轻松实现应用的多语言支持。

示例(默认英语 strings.xml):

<resources>
    <string name="hello">Hello</string>
    <string name="world">World</string>
</resources>

对应的中文版本(放在 res/values-zh/strings.xml):

<resources>
    <string name="hello">你好</string>
    <string name="world">世界</string>
</resources>

定义应用名称

作用:设置在设备上显示的应用名称。

示例:

<resources>
    <string name="app_name">My Awesome App</string>
</resources>

存储配置相关的字符串

作用:存储一些配置相关的字符串,如 API 端点、默认值等。

示例:

<resources>
    <string name="api_base_url">https://api.myapp.com/v1/</string>
    <string name="default_username">guest</string>
</resources>

定义格式化字符串

作用:创建包含占位符的字符串,可以在运行时动态填充。

示例:

<resources>
    <string name="welcome_user">Welcome, %1$s!</string>
    <string name="items_count">You have %1$d items in your cart</string>
</resources>

定义字符串数组

作用:创建一组相关的字符串,可以在代码中作为数组使用。

示例:

<resources>
    <string-array name="weekdays">
        <item>Monday</item>
        <item>Tuesday</item>
        <item>Wednesday</item>
        <item>Thursday</item>
        <item>Friday</item>
        <item>Saturday</item>
        <item>Sunday</item>
    </string-array>
</resources>

定义复数字符串

作用:根据数量自动选择正确的字符串形式。

示例:

<resources>
    <plurals name="numberOfSongsAvailable">
        <item quantity="one">%d song found.</item>
        <item quantity="other">%d songs found.</item>
    </plurals>
</resources>

存储不应硬编码在代码中的文本

作用:将一些可能需要频繁更改或者由非开发人员编辑的文本存储在 strings.xml 中。

示例:

<resources>
    <string name="terms_and_conditions">By using this app, you agree to our Terms of Service and Privacy Policy.</string>
    <string name="about_us">Our company was founded in 2023 with the mission to make the world a better place through technology.</string>
</resources>

综合示例:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 应用名称 -->
    <string name="app_name">My React Native App</string>

    <!-- 通用字符串 -->
    <string name="welcome_message">Welcome to our app!</string>
    <string name="login">Login</string>
    <string name="signup">Sign Up</string>

    <!-- 格式化字符串 -->
    <string name="welcome_user">Hello, %1$s!</string>
    <string name="items_in_cart">You have %1$d items in your cart</string>

    <!-- 字符串数组 -->
    <string-array name="color_options">
        <item>Red</item>
        <item>Green</item>
        <item>Blue</item>
    </string-array>

    <!-- 复数字符串 -->
    <plurals name="notification_count">
        <item quantity="one">You have %d new notification</item>
        <item quantity="other">You have %d new notifications</item>
    </plurals>

    <!-- 配置相关字符串 -->
    <string name="api_base_url">https://api.myapp.com/v1/</string>

    <!-- 长文本 -->
    <string name="privacy_policy">This is a long text about our privacy policy...</string>
</resources>

通过使用 strings.xml 文件,我们可以更好地组织和管理应用中的文本资源,支持多语言,并使代码更加清晰和易于维护。在 React Native 中,我们可以通过原生模块或第三方库(如 react-native-localization)来访问这些字符串资源。

总结

本文详细介绍了React Native Android开发中的核心配置和应用结构。我们探讨了AndroidManifest.xml的关键作用,包括应用信息定义、权限声明和组件配置。我们还分析了build.gradle文件在项目和应用模块级别的重要性,涵盖了从版本控制到依赖管理的各个方面。

在应用结构部分,我们深入研究了MainApplication类的实现,包括React Native环境的设置、第三方库的初始化以及调试工具的配置。最后,我们讨论了strings.xml在资源管理和本地化中的重要作用。

通过理解和正确配置这些核心元素,开发者可以构建更加健壮、高效和易于维护的React Native Android应用。记住,良好的配置和结构设计是开发成功应用的基础,它们不仅影响应用的性能和功能,还直接关系到开发过程的效率和可扩展性。