ReactNative 在丁香医生项目中引入的踩坑日记
this没绑定到函数导致空指针
参考
React-Native 踩坑第二弹-undefined is not a function(evaluating 'this.setState(...))
为什么在es6在这种情况下不需要bind this
React Native绑定this(bind(this) ES5语法React.createClass会自动绑定this,ES6的写法,不再自动绑定this。
React:ES6:ES7中的6种this绑定方法
说明
1、ES5语法React.createClass会自动绑定this,ES6的写法,不再自动绑定this
2、可以在constructor中进行this绑定
3、如果将自定义的函数写成箭头函数形式则会自动绑定this
异常
undefined is not a function(evaluating 'this.setState(...))
错误代码
export default class App extends Component<Props> {
//省略N多代码
//点击事件
_pressRow(rowToastMsg){
ToastAndroid.show(rowToastMsg,ToastAndroid.SHORT);
}
//this._pressRow(rowData)} 处报this空指针
_renderRow(rowData) {
return (
<TouchableOpacity onPress={() => this._pressRow(rowData)}>
<Text style={{fontSize:40}}>
{rowData}
</Text>
</TouchableOpacity>
);
}
解决方案
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged:(r1,r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
'全部科室',
])
};
//在构造器中添加下面这句代码
this._renderRow = this._renderRow.bind(this);
}
npm install异常——npm ERR! Unexpected end of JSON input while parsing near
异常
npm install
npm WARN deprecated connect@2.30.2: connect 2.x series is deprecated
npm ERR! Unexpected end of JSON input while parsing near '...5716bd740fd2","size":'
参考网址
npm install异常:npm ERR! Unexpected end of JSON input while parsing near
解决方案
npm cache clean --force
npm install
查看的配置npm代理
参考网址
查看npm配置文件路径
npm config get userconfig
设置npm代理
vim /Users/ybf326/.npmrc
添加如下内容
proxy=http://127.0.0.1:8118/
https-proxy=http://127.0.0.1:8118
注释可以使用#号,代理设置完成记得重新打开一下终端
连接数过多异常—— npm ERR! 503 Too many open connections
参考网址
python mechanize( HTTP Error 503: Too many open connections)
异常
当执行 npm install 时,出现 npm ERR! 503 Too many open connections 异常
解决方案
可能是代理对连接数做了限制,关闭代理,或者更换代理
android react-native run-android无法安装异常
异常
Building and installing the app on the device (cd android && ./gradlew installDebug)...
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html
可能原因
gradlew没有运行权限
解决方案
chmod +x gradlew
alert(this.props.navigation) 的 navigation 始终为 undefined
主要原因
没有正确配置如下代码
AppRegistry.registerComponent('AspirinPageProject', () => myStackNavigator);
上述代码解析
AspirinPageProject是你项目执行init的时候的名字
myStackNavigator是类型为StackNavigator的常量
关于myStackNavigator的创建方法
示例
const myStackNavigator = StackNavigator({
MyHome: {screen: HomeScreen},
SectionGroupActivity: {screen: SectionGroupActivityScene},
});
MyHome 名字可以随便取,StackNavigator 会默认加载第一个screen作为根视图
SectionGroupActivity 名字也可以随便取,不过,下面调用 navigate方法时,需要使用此名字
const {navigate} = this.props.navigation;
navigate("SectionGroupActivity");
screen为固定类型,HomeScreen 和 SectionGroupActivityScene 为类名
例如:
export default class SectionGroupActivityScene extends Component {
static navigationOptions = {
title: 'SectionGroupActivityScene',
//旧版-隐藏NavigationBar
//visible: false
//新版-隐藏NavigationBar
header: null,
};
render() {
return (
<View >
<Text>ChatScreen界面</Text>
</View>
);
}
}
使用教程 react-navigation
1、安装react-navigation
yarn add react-navigation
or
npm install --save react-navigation
2、删除index.js所有内容,添加为如下内容
import './App'
3、修改App.js的最顶部,导入必要的类
import {
Platform,
StyleSheet,
Text,
View,
ListView,
TouchableOpacity,
ToastAndroid,
AppRegistry
} from 'react-native';
import SectionGroupActivityScene from "./SectionGroupActivityScene";
import {StackNavigator} from 'react-navigation';
4、修改App.js的默认类名为HomeScreen(也可以保留类名为App)
5、修改HomeScreen类的首行,设置如下NavigationBar的选项
static navigationOptions = {
//NavigationBar标题
title: 'SectionGroupActivityScene',
//旧版-隐藏NavigationBar
//visible: false
//新版-隐藏NavigationBar
//header: null,
};
6、在App.js最底部,创建myStackNavigator常量对象,类型为StackNavigator。并注册为项目的根对象。
const myStackNavigator = StackNavigator({
MyHome: {screen: HomeScreen},
SectionGroupActivity: {screen: SectionGroupActivityScene},
});
//默认打开 SectionGroupActivityScene 界面
//AppRegistry.registerComponent('AspirinPageProject', () => SectionGroupActivityScene);
//默认打开导航器(这才是我们需要的)
AppRegistry.registerComponent('AspirinPageProject', () => myStackNavigator);
7、在TouchableOpacity的onPress方法(如 _pressRow 方法)中使用navigate进入跳转导航
//点击事件
_pressRow = (rowToastMsg) => {
const {navigate} = this.props.navigation;
navigate("SectionGroupActivity");
//alert(this.props.navigation);
}
fetch函数出现异常
异常
react native TypeError: Network request failed
参考网址
react native 使用fetch进行网络请求(https),解决SSLHandshake问题,以及怎样进行二次封装
可能的解决方案
如果你正在使用Charles.app设置代理抓包,请立即停止
如果你的服务端证书是非法的,请立即更换
你可以封装并调用原生方法或者使用其它方法来获取网络数据,而非使用fetch函数
fetch无网络时异常 —— React Native no internet fetch crashes
异常
react native fetch attempt to invoke virtual method on a null object reference
解决方案
调用fetch之前,一定记得检查网络状态
先添加Android网络状态访问权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
检查并监听网络状态示例
//检查网络状态,调用数据请求函数
//不检查网络状态,直接fetch,应用可能crash
checkConnectionState = () => {
NetInfo.isConnected.fetch().then(isConnected => {
if(isConnected){
this.getSectionList();
}else{
NetInfo.isConnected.addEventListener(
'connectionChange',
handleFirstConnectivityChange.bind(this)
);
alert("当前网络未连接,请连接网络");
}
});
function handleFirstConnectivityChange(isConnected) {
if(isConnected){
//移除监听器本身
NetInfo.isConnected.removeEventListener(
'connectionChange',
handleFirstConnectivityChange
);
ToastAndroid.show("网络已连接,正在为您加载最新数据",ToastAndroid.SHORT);
this.getSectionList();
}
}
}
//获取所有科室数据
getSectionList = () => {
}
关于使用了getInitialState函数后,this.state为null的问题
原因
React在ES6的实现中去掉了getInitialState这个hook函数,规定state在constructor中实现
在已有项目中引入React Native的坑
gradle.properties中添加参数
android.useDeprecatedNdk=true
app模块的build.gradle修改
android-defaultConfig节点
ndk {
abiFilters "armeabi-v7a"
}
android节点
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(com.android.build.OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
准备使用react native的模块(如果只有一个app模块,则可以在同一模块中修改)添加依赖信息
+号表示依赖最新版,也可以指定明确的版本号,+号有问题可以改成具体版本号
compile "com.facebook.react:react-native:0.55.3"
准备使用react native的模块添加依赖的下载位置(远方的maven库可能更新不及时,所以需要使用本地仓库),修改本模块的build.gradle
apply plugin: 'com.android.library'
apply from: "../../aspirin-2016/node_modules/react-native/react.gradle"
添加maven库路径,修改根项目(app模块外面一层)下的build.gradle
allprojects-repositories节点
maven {
url "$rootDir/node_modules/react-native/android"
}
准备使用react native的模块修改build.gradle
android-defaultConfig节点
ndk {
abiFilters "armeabi-v7a"
}
android节点
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a"
}
}
离线bundle打包脚本
react-native bundle --platform android --dev false --entry-file ReactSectionGroupActivityForReactRootView.js --bundle-output android/allbundle/index.android.bundle --assets-dest android/app/build/intermediates/res/merged/debug
核心类的创建
private static ReactInstanceManager createReactInstanceManager(Application application){
List<ReactPackage> mReactPackages = new ArrayList<>();
mReactPackages.add(new MainReactPackage());
mReactPackages.add(new AspirinAppPackage());
ReactInstanceManager reactInstanceManager = ReactInstanceManager.builder()
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("ReactSectionGroupActivityForReactRootView")
.addPackages(mReactPackages)
.setUseDeveloperSupport(isDebug())
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
return reactInstanceManager;
}
index.android.bundle为打包时生成的离线bundle的名字
ReactSectionGroupActivityForReactRootView为入口js,也就是打开时去加载的js文件名
isDebug()为false才会加载asset中的离线bundle,为true时,会去访问本地服务端
网上文章:
Android项目集成React Native实践总结
so报空-react-native植入原生应用-踩坑记
关于so加载不到,libgnustl_shared.so加载错误的处理
异常如下
05-14 13:40:12.578 1506-26433/? E/ActivityTrigger: activityStartTrigger: not whiteListedcn.dxy.aspirin.reactnative.demo/cn.dxy.aspirin.reactnative.ReactSectionGroupActivityForReactRootView/1
05-14 13:40:12.579 1506-26433/? E/ActivityTrigger: activityResumeTrigger: not whiteListedcn.dxy.aspirin.reactnative.demo/cn.dxy.aspirin.reactnative.ReactSectionGroupActivityForReactRootView/1
05-14 13:40:12.585 1506-26433/? E/ActivityTrigger: activityResumeTrigger: not whiteListedcn.dxy.aspirin.reactnative.demo/cn.dxy.aspirin.reactnative.ReactSectionGroupActivityForReactRootView/1
05-14 13:40:12.832 12756-12810/cn.dxy.aspirin.reactnative.demo E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: cn.dxy.aspirin.reactnative.demo, PID: 12756
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/cn.dxy.aspirin.reactnative.demo/lib-main/libgnustl_shared.so" is 32-bit instead of 64-bit
at java.lang.Runtime.load0(Runtime.java:928)
at java.lang.System.load(System.java:1621)
at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:71)
at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:65)
at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:65)
at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:65)
at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:247)
at com.facebook.react.bridge.ReactBridge.staticInit(ReactBridge.java:18)
at com.facebook.react.bridge.NativeMap.<clinit>(NativeMap.java:19)
at com.facebook.react.bridge.JSCJavaScriptExecutorFactory.create(JSCJavaScriptExecutorFactory.java:21)
at com.facebook.react.ReactInstanceManager$5.run(ReactInstanceManager.java:912)
at java.lang.Thread.run(Thread.java:764)
05-14 13:40:12.852 1506-1592/? E/ANDR-PERF-JNI: com_qualcomm_qtiperformance_native_perf_io_prefetch_start
05-14 13:40:12.852 747-747/? E/ANDR-IOP: IOP HAL: Received pkg_name = cn.dxy.aspirin.reactnative.demo pid = 12756
05-14 13:40:12.853 747-810/? E/ANDR-IOP: io prefetch Capture is deactivated
05-14 13:40:12.860 1914-1914/? E/Icon: Unable to load resource 0x00000000 from pkg=com.android.systemui
android.content.res.Resources$NotFoundException: Resource ID #0x0
at android.content.res.ResourcesImpl.getValueForDensity(ResourcesImpl.java:220)
at android.content.res.Resources.getDrawableForDensity(Resources.java:889)