React Native安卓端的一些注意事项
2017-01-12 by erhutime

React-native for Android:

标签: react-native


1. 前言

React-native是目前最火的一种APP混合开发语言。本文旨在帮助一些不熟悉安卓原生开发的程序员快速熟悉安卓目录结构。
使用工具:
js--WebStorm;
安卓原生--Android Studio;


2. 目录结构

--1:新建一个React-native项目,并把项目分别导入到WebStorm,Android Studio中,目录如下:

--2:安卓基本组件进行介绍:
Activity:
一个Activity是一个应用程序组件,提供一个屏幕,用户可以用来展示或者交互去完成某件事情。一个应用程序通常由多个activities组成,他们通常是松耦合关系。通常,一个应用程序中的activity被指定为"main"activity,当第一次启动应用程序的时候呈现给用户的那个activity。每一个activity可以启动另一个activity为了完成不同的动作。每一次一个activity启动,前一个activity就停止了,但是系统保留activity在一个栈上(“backstack”)。当一个新activity启动,它被推送到栈顶,取得用户焦点。BackStack符合简单“后进先出”原则,所以,当用户完成当前activity然后点击back按钮,它被弹出栈(并且被摧毁),然后之前的activity恢复,activity的生命周期执行。

当一个activity因新的activity启动而停止时,它的状态就会发生变化而代码层次上来说就是activity生命周期回调函数在不同时机执行。回调函数在一个activity可能会被执行多次,不同的回调函数提供完成适合这个状态的指定操作。例如,当停止的时候,activity应该释放任何大的对象,例如网络数据库连接。当activity恢复,可以重新获得必要的资源和恢复被中断的动作。这些状态转换都是activity的生命周期的部分。
  
  创建一个activity,必须创建一个activity的子类。安卓版本高于23时,需要继承自AppCompatActivity否则继承自Activity。

Fragment:
Fragment是activity的界面中的一部分或一种行为。可以把多个Fragment组合到一个activity中来创建一个多界面
并且可以在多个activity中重用一个Fragment。可以把Fragment任务模块化的一段activity,它具有自己的生命周期,
接收它自己的事件,并可以在activity运行时被添加或删除。
Fragment不能独立存在,它必须嵌入到activity中,而且Fragment的生命周期直接受所在的activity的影响。例
如:当activity暂停时,他拥有的所有的Fragment都暂停了,当activity销毁时,他拥有的所有Fragment都被销毁。然
而,当activity运行时(在onResume()之后,onPause()之前),可以单独地操作每个Fragment,比如添加或删除它
们。当中执行上述针对Fragment的事务时,可以将事务添加到一个栈中,这个栈被activity管理,栈中的每一条都是一
个Fragment的一次事务。有了这个栈,就可以反向执行Fragment的事务,这样就可以在Fragment级支持“返回”键
(向后导航)。
当向activity中添加一个Fragment时,它须置于ViewGroup控件中,并且需定义Fragment自己的界面。可以在
layout.xml布局文件中声明Fragment,元素为:<fragment>;也可以在代码中创建Fragment,然后把它加入到
ViewGroup控件中。然而,Fragment不一定非要放在activity的界面中,它可以隐藏在后台为activity工作。

AndroidManifest.xml:清单文件
1-:权限控制<上网权限等>
2-:Activity和Service等需要注册

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

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

<uses-sdk
    android:minSdkVersion="16"
    android:targetSdkVersion="22" />

<application
  android:name=".MainApplication"
  android:allowBackup="true"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:theme="@style/AppTheme">
  <activity
    android:name=".activity.MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
  <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>

</manifest>

从这个文件中可以看出:
1-:安卓应用的包名:package="com.keynote"
2-:安卓APP的版本号:android:versionCode="1"
android:versionName="1.0"
3-:权限:上网权限和系统弹出框权限

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

4-:此APP需要运转在最低和最高的安卓系统

<uses-sdk
    android:minSdkVersion="16"
    android:targetSdkVersion="22" />

5-:此应用在手机桌面上显示的名字:

android:label="@string/app_name"

6-:此应用在手机桌面上的图标:

android:icon="@mipmap/ic_launcher"

7-:此应用在手机上的主题样式:

 android:theme="@style/AppTheme"

8-:原生应用的启动的第一个Activity<此处名字是:MainActivity>

<activity
    android:name=".activity.MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>

9-:调试,可以在正式发布时进行删除:

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

--3:包的导入:
package com.keynote:表示这个文件所在的项目中的具体路径;
import android.XXXXX;表示导入的泪或者方法或者对象是安卓原生自带的;
import java.util.XXXX; 表示使用的方法或者是或者对象是Java自带的;
未导入相关需要的对象或者类时,系统会在缺少的累下面画红线并报错。

package com.keynote;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
  return BuildConfig.DEBUG;
}

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
      new MainReactPackage()
  );
  }
 };

 @Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}

@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this,false);
 }
}

-4:关于build.gradle:
Android Studio是通过Gradle来管理第三方。所以,我们需要熟悉基本的配置信息;
在安卓目录下,存在两个build.gradle文件,一个是根目录,一个存在在APP包下面的;
存在APP目录下的build.gradle:

  android {
  //安卓编译系统
  compileSdkVersion 23
  buildToolsVersion "23.0.1"

defaultConfig {
    //报名表
    applicationId "com.keynote"
    minSdkVersion 16
    targetSdkVersion 22
    versionCode 1
    versionName "1.0"
    //ndk开发时支持的芯片
    ndk {
        abiFilters "armeabi-v7a", "x86"
    }
}

//依赖的第三方包
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+"  // From    node_modules
 }

根目录下的build.gradle:

dependencies {
    //版本号:
    classpath 'com.android.tools.build:gradle:2.1.2'
}

通常,我们会静态设置gradle的版本:
在项目目录下的gradle/wrapper/gradle-wrapper.propertis中:
distributionUrl=https://services.gradle.org/distributions/gradle-2.14-all.zip

-5:关于Jdk,Sdk:<也可以通过setting设置路径>
在项目目录下的:local.propertis中:
ndk.dir=/Users/erhu/Library/Android/sdk/ndk-bundle
sdk.dir=/Users/erhu/Library/Android/sdk

3. 开发常见需求

-1:修改APP名字<一些使用文件的目录>
1--package.json
2--index.android.js
3--android/settings.gradle
4--android/app/build.gradle;
5--android/app/src/main/java/{projectname}
6--android/app/src/main/java/{projectname}/MainActivity
7--android/app/src/main/AndroidManifest.xml

android:label="@string/app_name"

8--android/app/src/main/res/valuse/strings.xml

 <string name="app_name">AwesomeProject</string>

7与8,需要保证一致!
若只是想修改应用的名字,直接执行7,8即可!把AwesomeProject修改成你想要的名字。

-2:图标
1--确认
android/app/src/main/res/mipmap--xxx,
或者
android/app/src/main/res/drawable--xxx
每一个目录下有不同大小的图标-- xxx.png<适配安卓不同机型>
2--android/app/src/main/AndroidManifest.xml
当放入的是mipmap,

android:icon="@mipmap/xxx"

当放入的是drawable

android:icon="@drawable/xxx"

-3:包名:
android/app/src/main/AndroidManifest.xml

package="com.awesomeproject"

修改包名如下:
1--android/app/src/main/AndroidManifest.xml
2--android/app/build.gradle;

defaultConfig{
applicationId  “packagename”
}

3--android/app/build/generated/source/buildConfig/debug/{packagename}/BuildConfig;

public static final String APPLICATION_ID = "packagename";

注意观察目录结构
假设之前包名为“aaa.bbbbbb”,在编辑器里分为两层,而在Android Studio编辑器里面只有一层;
当你要把包名修改成“aaa.bbbbbb.ccc”的时候,需要在编辑器里,新建一个文件夹名字为“ccc”,把之前在“bbbbbb”目录下的文件放入到新建文件夹里面,成为它的子目录,然后关闭项目编辑器,重启!

注意:不管使用什么编辑器,修改后的包名需要同步到RN项目下的目录结构,注意层级结构!

-4:运行:
1-:通过CMD命令行来运行<项目根目录>:
npm start
react-native run-android:

查看本地服务器是否正常启动在浏览器输入:

验证本地服务启动:http://localhost:8081/index.android.bundle?platform=android

2-:通过Android Studio运行项目:
需要在根目录执行如下命令:

 react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

注意:assets文件需要根据具体路径进行调整,执行本命令之前,需要去检查文件是否存在,若不存在,则需要新建。

4. 新建项目目录个别类

1-:
MainActivity是项目新建之后系统默认的一个类,ReactActivity不属于安卓原生的Activity类;
直接运行APP,此类不能类似原生Activity把页面展示到手机屏幕上;

package com.keynote.activity;
import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
    return "KeyNote";
}
}

2-:真正意思上Application才是APP的入口,可以在这里进行一些大数据的初始化等其他操作。
实现ReactApplication一些方法,为原生代码和JavaScript交互提供帮助;

package com.keynote;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
  return BuildConfig.DEBUG;
}

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
      new MainReactPackage()
  );
}
 };

 @Override
   public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
 }

 @Override
 public void onCreate() {
super.onCreate();
SoLoader.init(this,false);
  }
}
[去论坛发表意见]