React NativeiOS笔记React-Native相关

ReactNative封装iOS/Android原生组件

2018-07-20  本文已影响30人  kyleBoy

简介

为了提高代码的复用,减少重复工作,我们经常会把比较独立的功能模块封装成组件或者library

在iOS我们通常封装为静态库(.framework和.a),

在Android中我们通常封装为Android Library(gradle模块),

在JavaScript中我们通常封装成node package,

而在ReactNative中我们要封装与原始有关的库我们需要,结合iOS静态库(.a)、Android Library和node package一起封装成ReactNative用的node package。

目录结构

testmodule-wyh
.
├── android   // 存放Android library
│   ├── build
│   ├── build.gradle
│   ├── libs
│   ├── proguard-rules.pro
│   ├── src
│   └── testmodule.iml
├── component // 存放js桥接过来的组件以及api
│   └── TestView.js
├── index.js
├── ios // 存放iOS library
│   ├── TestModule
│   └── TestModule.xcodeproj
└── package.json // node包的配置文件

源码地址

制作

装备工作

创建ReactNative工程

我们需要先创建一个ReactNative工程,使用如下命令创建。

$ react native init A7011CreatNativeModule

创建存放封装库的目录

$ cd A7011CreatNativeModule/node_modules
$ mkdir testmodule-wyh
$ cd testmodule-wyh
$ mkdir ios
$ mkdir android
$ mkdir component

封装iOS库

步骤

1. 静态库创建

由于ReactNative的组件都是一个个静态库,我们发布到npm给别人使用的话,也需要建立静态库。我们使用xcode建立静态库,取名为Testmodule。建立之后,我们将创建的静态库中的文件全部copy到node_modules/Testmodule/ios目录下。 ios文件目录如下:

testmodule-wyh
.
├── android   // 存放Android library
├── component // 存放js桥接过来的组件以及api
└── ios // 存放iOS library
    ├── Testmodule
    │   ├── Testmodule.h
    │   └── Testmodule.m
    └── TestModule.xcodeproj
2. 引入到目标工程

使用xcode打开A7011CreatNativeModule/ios/下的iOS工程,将BGNativeModuleExample静态库工程拖动到工程中的Library中。

image-20180713184731573
  1. 为什么要拖到RN工程中呢?

    因为,不拖到RN工程中去的话,用的RN库中的API,就会报错,所以需要RN工程的基础环境。

  2. 为什么这里要先把静态库放到node_modules/Testmodule/ios,再拖到RN工程中去呢?

    那是因为,如果直接把创建的静态库的TestModule.xcodeproj文件拖到工程中去,无法编辑这个静态库,只有在node_modules/Testmodule/ios才能编辑。目前还不知道原因

3. 编写原生代码

咱们这里主要是演示做封装RN的node package,所以就封装一个最简单的组件,一个背景色为红色的View。

  1. 创建TestView Class

       // TestView.h
       #import <UIKit/UIKit.h>
       
       @interface TestView : UIView
           
       @end
       
           
       // TestView.m
       #import "TestView.h"
       
       @implementation TestView
       - (instancetype)init
       {
           self = [super init];
           if (self) {
               self.backgroundColor = [UIColor redColor];
           }
           return self;
       }
       
       @end    
    
  2. 创建桥接类

    // TestViewManager.h
    #import <React/RCTBridgeModule.h>
    
    @interface TestViewManager : RCTViewManager <RCTBridgeModule>
    
    @end
        
        
    // TestViewManager.m
    #import "TestViewManager.h"
    #import <React/RCTViewManager.h>
    #import "TestView.h"
    
    @interface TestViewManager : RCTViewManager
    @end
    
    @implementation TestViewManager
    
    RCT_EXPORT_MODULE()
    
    - (UIView *)view
    {
        return [[TestView alloc] init];
    }
    
    @end
    
    
  3. 需要更复杂的交互,可以参考React Native官网的iOS原生模块原生UI组件

4. React组件创建
  1. 接下来你需要一些Javascript代码来让这个视图变成一个可用的React组件:

    // A7011CreatNativeModule/node_modules/testmodule-wyh/component/TestView.js
    // TestView.js
    import {requireNativeComponent} from 'react-native';
    
    const TestView = requireNativeComponent('TestView', null);
    export default TestView;
    
  2. 在路径A7011CreatNativeModule/node_modules/testmodule-wyh创建index.js文件,导出TestView组件

    // index.js
    import TestView from './component/TestView'
    
    export default TestView;
    
5. 组件使用

在RN工程里面的App组件中,使用这个组件

// App.js
import React, {Component} from 'react';
// ......
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
      // ......
        <TestView style={{width: 100, height: 100}} /> // TestView组件
      </View>
    );
  }
}
// ......
});

6. 运行效果
image

注意

引入第三方库

iOS封装静态库的时候,经常会用到需要引入的系统库和第三方库;系统库引入很简单,只要在TestModule.xcodeproj->Build Phases->Link Bnary with Libraries添加系统库就行;而第三方库有可能是.a也有可能是.framework,.a拷贝到静态库根目录里面,接下就和系统库添加一样了,而.framework就复杂了,他不能直接引用到封装的静态库中,需要引用到目标iOS工程中去才可以。

桥接ViewController

封装Android库

步骤

1. 创建Android library

用Android studio打开RN工程中的Android工程,新建file->new->new module..->Android library,并命名为testmodule

image-20180716164450271
2. RN的Android工程中配置模块
3. 编写原生代码

Android原生代码的编写,前两步和iOS步骤类似,多了一个创建ReactPackage实现,并在MainApplication的getPackages方法里面注册。

  1. 创建TestView Class

    package com.example.testmodule;
    
    import android.content.Context;
    import android.graphics.Color;
    import android.view.View;
    
    public class TestView extends View {
    
        public TestView(Context context) {
            super(context);
            this.setBackgroundColor(Color.rgb(255,0,0));
        }
    }
    
  2. 创建桥接类

    package com.example.testmodule;
    
    import com.facebook.react.uimanager.SimpleViewManager;
    import com.facebook.react.uimanager.ThemedReactContext;
    
    public class TestViewManager extends SimpleViewManager<TestView> {
        public static final String REACT_CLASS = "TestView";
    
        @Override
        public String getName() {
            return REACT_CLASS;
        }
    
        @Override
        protected TestView createViewInstance(ThemedReactContext reactContext) {
            return new TestView(reactContext);
        }
    }
    
    
  3. 需要创建一个Package注册类

    package com.example.testmodule;
    
    import com.facebook.react.ReactPackage;
    import com.facebook.react.bridge.NativeModule;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.uimanager.ViewManager;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class TestPackage implements ReactPackage {
        @Override
        public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            List<ViewManager> modules = new ArrayList<>();
            modules.add(new TestViewManager());
            return modules;
        }
    }
    
  4. 在MainApplication.java中注册这个package

    package com.a7011creatnativemodule;
    // ......
    public class MainApplication extends Application implements ReactApplication {
      private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
       //.......
        @Override
        protected List<ReactPackage> getPackages() {
          return Arrays.<ReactPackage>asList(
              new MainReactPackage(),
              new TestPackage(),
              // .......
          );
        }
     //.......
      };
    
      //.......
    }
    
    
  5. 需要更复杂的交互,可以参考React Native官网的android原生模块原生UI组件

4. 组件创建使用

之后的步骤在封装iOS库的4、5、6步已经做了

5. 运行效果

直接在点击run,看结果


image

注意

Gradle问题
  1. com.android.tools.build:gradle工具也有2升级为3以后,dependencie依赖由compile变为implementation,而用React Native init ProjectName创建的rn项目还是用的compile,所以创建的时候要调整Gradle.build的dependencie和minSdkVersion以适用目标项目。
  2. 一定要记得创建ReactPackage的接口实现类,这样当执行react-native link testmodule-wyh才会自动添加到依赖。

整理成node package

  1. 将封装的Android library里面的所以文件移到node_modules/Testmodule/android里面,形成的目录结构如下:

    .
    ├── android
    │   ├── build.gradle
    │   ├── libs
    │   ├── proguard-rules.pro
    │   ├── src
    │   ├── androidTest
    │   ├── main
    │   │   ├── AndroidManifest.xml
    │   │   ├── java
    │   │   │   └── com
    │   │   │       └── example
    │   │   │           └── testmodule
    │   │   │               ├── TestPackage.java
    │   │   │               ├── TestView.java
    │   │   │               └── TestViewManager.java
    │   │   └── res
    │   │       ├── drawable
    │   │       └── values
    │   │           └── strings.xml
    │   └── test
    │   └── testmodule.iml
    ├── component
    │   └── TestView.js
    ├── index.js
    ├── ios
    │   ├── TestModule
    │   │   ├── TestView.h
    │   │   ├── TestView.m
    │   │   ├── TestViewManager.h
    │   │   └── TestViewManager.m
    │   └── TestModule.xcodeproj
    
  2. 在路径node_modules/Testmodule-wyh/使用npm init创建一个package.json文件,全部使用默认项就行,这样Testmodule-wyh node package就封装完成了。

    // package.json
    {
      "name": "testmodule-wyh",
      "version": "1.0.0",
      "description": "test",
      "main": "index.js",
      "directories": {
        "lib": "lib"
      },
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }
    
    

使用

  1. testmodule-wyh node package拷贝到桌面,然后将iOS和Android项目中与Testmodule-wyh有关的代码全部删除

  2. 在RN项目中package.json中使用本地路径的方式引用制作的testmodule-wyh node package

    // package.json
    {
      "name": "A7011CreatNativeModule",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "node node_modules/react-native/local-cli/cli.js start",
        "test": "jest"
      },
      "dependencies": {
        "react": "16.4.1",
        "react-native": "0.56.0",
        "testmodule": "file:/Users/wangyinghui/Desktop/testmodule-wyh",
      },
      "devDependencies": {
        "babel-jest": "23.4.0",
        "babel-preset-react-native": "^5",
        "jest": "23.4.0",
        "react-test-renderer": "16.4.1"
      },
      "jest": {
        "preset": "react-native"
      }
    }
    
  3. 在RN项目根目录执行如下指令

    $ yarn install
    $ react-native link testmodule-wyh
    
  4. 看到如下提示表示成功

    image
  5. 运行iOS和Android查看效果

    $ react-native run-android
    $ react-native run-ios
    

注意事项

  1. iOS和Android的命名不一定要和封装的node package名一直。

  2. 默认iOS和Android的library都要在根目录,如果不在根目录需要在packag.json指明如下

    {
      "name": "react-native-maps",
      // ...
      "rnpm": {
        "android": {
          "sourceDir": "./lib/android"
        }
      }
    }
    

上传代码库

GitHub,创建一个代码仓库,将node package 代码上传,然后在package.json添加repository如下:

"repository" :  
  { 
      "type" : "git",
      "url" : "https://github.com/<yourusername>/testmodule-wyh.git"  
  }  

repository 属性不写也可以,但是最好建一个 github 项目然后把地址写进来,方便以后维护。

发布

注册npm账号

发布node package到npm服务器上,需要npm的账号,注册哪怕npm账号有两种形式

如果用命令行注册的话,最好是在npm官网验证一下

登录npm账户

首次需要登录,npm login(需要输入用户名,密码,还有邮箱) 存储证书到本地,后面就不需要每次都登录的

$ npm login
Username: wangyinghui
Password: 
Email: (this IS public) iyinghui@163.com
Logged in as wangyinghui on http://registry.npmjs.org/.

开始发布

$ npm publish
+ testmodule-wyh@1.0.2

发布时报错

1. cnpm造成的报错

$ npm publish
npm ERR! registry error parsing json
npm ERR! publish Failed PUT 413
npm ERR! Unexpected token < in JSON at position 0
npm ERR! <html>
npm ERR! <head><title>413 Request Entity Too Large</title></head>
npm ERR! <body bgcolor="white">
npm ERR! <center><h1>413 Request Entity Too Large</h1></center>
npm ERR! <hr><center>nginx/1.4.6 (Ubuntu)</center>
npm ERR! </body>
npm ERR! </html>
npm ERR! 

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/wangyinghui/.npm/_logs/2018-07-13T02_27_29_082Z-debug.log

出现原因:使用的是淘宝源cnpm,登陆到的是cnpm

解决方法:切换到npmjs的网址,代码如下:

$ npm config set registry http://registry.npmjs.org/

发布完成之后,如果还想回到之前的cnpm,使用下面的命令

$ npm config set registry https://registry.npm.taobao.org

npm 安装git项目的几种方式

1. 直接通过用户名安装

#   直接利用用户名与仓库名进行安装
$ npm install yiifaa/yii-es6-amd
#   或者为了提醒自己,加上github前缀进行区分
$ npm install github:yiifaa/yii-es6-amd1234

2. 通过地址安装

#   这样适合安装公司内部的git服务器上的项目
$ npm install git+https://git@github.com/yiifaa/yii-es6-amd.git#v1.0.0
#   或者以ssh的方式
$ npm install git+ssh://git@github.com/yiifaa/yii-es6-amd.git#v1.0.0

参考文章

上一篇下一篇

猜你喜欢

热点阅读