封装自定义Rn组件
未搭建0.58.6开发环境的小伙伴阔以查看上篇文章:Android原生集成RN
组件目录结构
── android // 存放Android library
│ ├── build
│ ├── build.gradle
│ ├── libs
│ ├── proguard-rules.pro
│ ├── src
├── js // 存放js桥接过来的组件以及api
│ └── JMVideoLineView.js
├── index.js
├── ios // 存放iOS library
│ ├── TestModule
│ └── TestModule.xcodeproj
└── package.json // node包的配置文件
封装IOS(此处没实现在Android收集手机也是可以)
封装Android
1、创建Android Library
用Android studio打开RN工程中的Android工程,新建file->new->new module…->Android library,并命名为react-native-videolineview-jm
2、配置依赖
在app工程中的build.gradle文件中的dependencies添加一行
implementation project(':react-native-videolineview-jm')
让主工程app依赖我们新创建的Library。然后需要在我们新创建的react-native-videolineview-jm下的build.gradle中的dependencies添加一行
implementation "com.facebook.react:react-native:+"
就行了。
3、编写原生代码
public class JMVideoLineViewManager extends SimpleViewManager<VideoLineView> {
@Override
public String getName() {
return "JMVideoLineView";
}
@Override
protected VideoLineView createViewInstance(ThemedReactContext reactContext) {
return new VideoLineView((Context)(reactContext));
}
}
它继承自SimpleViewManager。ReactImageView是这个视图管理类所管理的对象类型,也就是我们自定义的原生视图。getName方法返回的名字会用于在 JavaScript 端引用
public class JMVideoLineViewPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.asList(
new JMVideoLineViewModule(reactContext)
);
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.asList(
new JMVideoLineViewManager()
);
}
}
原生代码写完把新创建的Library所有文件复制到node_modules/android 下,并在setting/gradle 配置
project(':react-native-videolineview-jm').projectDir = new File(rootProject.projectDir, './node_modules/react-native-videolineview-jm/android')
React组件创建
1、接下来你需要一些Javascript代码(JMVideoLineView.js,放在js文件夹)来让这个视图变成一个可用的React组件:
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
requireNativeComponent, View, UIManager,
findNodeHandle,
} from 'react-native';
var RCT_VIDEO_REF = 'JMVideoLineView';
class RNVideoLineView extends Component {
constructor(props) {
super(props);
}
render() {
return <JMF1VideoLineView
{...this.props}
/>;
};
}
VideoView.propTypes = {
...View.propTypes,
};
var JMVideoLineView = requireNativeComponent('JMVideoLineView', RNVideoLineView);
module.exports = RNVideoLineView;
创建 JavaScript 模块并且定义 Java 和 JavaScript 之间的接口层。我们建议你使用 Flow 或是 TypeScript 来规范定义接口的具体结构,或者至少用注释说明清楚(老版本的 RN 使用propTypes来规范接口定义,这一做法已不再支持)
2、在路径/node_modules/react-native-videolineview-jm创建index.js文件,导出JMVideoLineView组件
import _JMVideoLineView from './js/JMVideoLineView';
export const JMVideoLineView= _JMVideoLineView;
事件监听(Android)
native端
native端可以使用RCTEventEmitter将事件传递到JS端。基本的用法为
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(yourView.getId(), "topChange", event);
receiveEvent第一个参数是viewId,第二个参数是eventName,topChange对应JS接收属性为onChange,第三个参数是需要传递的event。 比如我们可以将JMVideoLineView滑动进度传递到JS端,并携带一个参数,如:
//VideoLineView.java
WritableMap eventMap = Arguments.createMap();
eventMap.putDouble("progress", time);
ReactContext reactContext = (ReactContext) getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
getId(),
// "onProgress",
"topChange",
eventMap
);
JS端
//JMVideoLineView.js
class RNVideoLineView extends Component {
_onChange(event) {
alert(event.nativeEvent.progress)//这里获取到传过来的值,就是对应的key
}
constructor(props) {
super(props);
}
render() {
return <JMVideoLineView
{...this.props}
onChange={this._onChange.bind(this)}
/>;
};
}
RNVideoLineView.propTypes = {
...View.propTypes,
};
var JMVideoLineView = requireNativeComponent('JMVideoLineView', RNVideoLineView,{nativeOnly:{onChange:true}});
module.exports = RNVideoLineView;
3 事件名称和JS端props对应关系
为什么事件名称topChange对应JS端onChange属性呢,好像也没有定义这个对应关系啊?其实在ViewManager中预先定义好了一些对应关系在UIManagerModuleConstants.java中:
//UIManagerModuleConstants.java
/* package */ static Map getBubblingEventTypeConstants() {
return MapBuilder.builder()
.put(
"topChange",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onChange", "captured", "onChangeCapture")))
.put(
"topSelect",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onSelect", "captured", "onSelectCapture")))
...
.build();
}
那如果我们想自己定义对应关系,该怎么做呢,其实很简单,只需要复写ViewManager中getExportedCustomDirectEventTypeConstants()方法就行了。
@Nullable
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("onProgress",
MapBuilder.of("registrationName", "onProgress"))
.build();
}
这样就把native和js关联起来了。
ReactProp 和 ReactMethod使用
1、ReactProp
要导出给 JavaScript 使用的属性,需要申明带有@ReactProp(或@ReactPropGroup)注解的设置方法。方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为void,而且访问控制必须被声明为public。JavaScript 所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:boolean, int, float, double, String, Boolean, Integer, ReadableArray, ReadableMap。
//JMVideoLineViewManager.java
@ReactProp(name = "lineColor")
public void setLineColor(VideoLineView videoLineView,String lineColor) {
videoLineView.setLineColor(lineColor);
}
@ReactProp(name = "centerLineColor")
public void setCenterLineColor(VideoLineView videoLineView,String centerLineColor) {
videoLineView.setmCenterlineColor(centerLineColor);
}
//js中使用
<JMVideoLineView
style={{height: 40, backgroundColor: '#000000'}}
lineColor={'#A7B1C5'}
centerLineColor={'#8690A8'}
onProgress={this._onProgress}
/>
2、ReactMethod使用
//JMVideoLineViewModule.java
@ReactMethod
public void startAutoRun(boolean isAutoRun){
}
在js中 JMVideoLineView.startAutoRun(true)
组件使用
在需要的页面import { JMVideoLineView } from ‘react-native-videolineview-jm’
<JMVideoLineView
style={{height: 40, backgroundColor: '#000000'}}
lineColor={'#A7B1C5'}
centerLineColor={'#8690A8'}
onProgress={this._onProgress} //这个是自定义监听
/>
发布组件
创建github 工程
创建名为react-native-videolineview-jm 的空工程,拉取到本地
创建package.json
cd 到node_module/react-native-videolineview-jm 输入npm init 输入信息后完成即可
推送到github
复制node_module下的react-native-videolineview-jm 到上一步创建的空工程,记住复制时要保留空工程的.gitinore 文件,然后推到github上
推到github遇到一个坑
Logon failed, use ctrl+c to cancel basic credential prompt.
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: Authentication failed for 'https://github.com/JimiPlatform/react-native-videolineview-jm.git/'
原因是August 13, 2021后 github 不支持密码验证操作仓库
解决方案参照:https://blog.csdn.net/weixin_41010198/article/details/119698015
推送到npm
npm config set registry http://registry.npmjs.org
npm login # 如果已经在官网有账号,可以直接登录
npm adduser # 创建 NPM 账号
npm whoami # 查看登录状态
输入npm login 遇到的坑:
npm ERR! code ETIMEDOUT
npm ERR! errno ETIMEDOUT
npm ERR! network request to http://registry.npmjs.org/-/v1/login failed, reason: connect ETIMEDOUT 104.16.17.35:80
npm ERR! network This is a problem related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly. See: 'npm help config'
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\zeng.weidie\AppData\Roaming\npm-cache\_logs\2021-09-24T10_17_46_831Z-debug.log
把代理关掉
npm publish
输入npm publish 遇到的坑
npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/lanke-template-h5 - Forbidden
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy.
npm ERR! A complete log of this run can be found in:
npm ERR! D:\NodeJS\node_cache\_logs\2020-11-27T03_42_41_070Z-debug.log
解决方案:首次注册,没有验证邮箱,去邮箱按步验证,再次发布即可解决
npm config set registry https://registry.npm.taobao.org
测试发布是否成功
删除node_module下的react-native-videolineview-jm,在Terminal中输入 yarn add react-native-videolineview-jm ,或者配置主工程package.json,使用yarn install,这会把配置文件中的所有组件拉取一遍。
源码:https://github.com/JimiPlatform/react-native-videolineview-jm
|