还有像这样的t5rn么,百度查病为啥越查越像老是不显示wwWt5rncom内榕

iOS-OC(422)
本文主要分享Android和iOS端升级RN到0.44.0版本的经验。
今天收到一封不知来自哪个国家的友人的感谢邮件,说是我之前的一篇文章帮助到了他,这才看了看自己的博客,发现我真的有很久没分享东西了。毕业一年有余,换了一次工作,一直忙忙碌碌,日子很充实,收获很多,其实真的很想都分享出来,但是周末却总是变得懒散不想动,慢慢地就积压了很多想分享的内容。这次终于战胜自己,重新开始分享,希望能够坚持下去。
首先,我要告诉大家一件事情,我正式开始做iOS啦,撒花~ 现在产品迭代中交给我的需求如果工作量不是很大的话,那么Android和iOS端就都交给我一个人搞啦,真好。
其次,我开始正式接触React Native啦,撒花again~ RN在我们的产品中也是比较重要的模块,首页以及多个二级界面都是RN完成的,体验还好,但是带来的crash也不少!
考虑到我们的RN版本有点老,问题较多,所以最近对RN进行一次升级,升级到0.44.0版本,并对Android和iOS的RN模块进行代码改造。期间我主要是完成Android和iOS端RN模块代码的改造工作,另一位前端同学配合一起解决升级过程出现的问题。
作为一个接到RN升级任务的RN小白,下面我就大致介绍下自己完成这个任务时遇到的坑,希望能有所帮助。
文中的代码和图片我都反复检查过了,基本上没有泄露公司的重要信息的数据,如若发现有泄露的话请立即告知我 ;-)
1.替换RN新版本的依赖库,同时更新相关配置
我们的项目不是直接基于RN开始的,而是已有的项目集成RN。此外,RN集成的方式也不是源码集成,而是使用RN源码编译生成的静态库。
(1)对于Android来说,项目中依赖的是RN源码下ReactAndroid项目构建得到的aar文件(你还可以继续精简成一个jar文件)。
如何生成这个aar文件呢?
按照官网教程下载RN源码并配置好RN环境之后,在源码根目录下新建gradle.properties文件(用来配置gradle的代理)和local.properties文件(用来指定sdk.dir和ndk.dir),执行./gradlew :ReactAndroid:installArchives即可看到源码下多了一个android目录,其中就放着我们需要的aar文件。默认的名称是-master,如果你想修改生成的aar的名称,可以通过修改ReactAndroid/gradle.properties文件中的VERSION_NAME来实现。
1.编译RN源码的时候需要配置NDK,版本必须是r10e,不能是更高版本,点击进入下载地址。
2.更新RN的aar文件之后,除了需要修改部分API的调用方式之外,还要修改gradle脚本中依赖库的版本号以及混淆规则!
compile 'javax.inject:javax.inject:1'
compile 'com.facebook.fbui.textlayoutbuilder:textlayoutbuilder:1.0.0'
compile 'com.facebook.fresco:fresco:1.0.1'
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.0.1'
compile 'com.facebook.soloader:soloader:0.1.0'
compile 'com.google.code.findbugs:jsr305:3.0.0'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'
compile 'com.squareup.okhttp3:okhttp-ws:3.4.1'
compile 'com.squareup.okio:okio:1.9.0'
compile 'org.webkit:android-jsc:r174650'
compile(name: 'react-native-0.44.0', ext: 'aar')
混淆规则 (注意最后一句,不加会产生问题,不过我觉得这可能不是解决问题最好的方式)
#============================= React Native start =============================#
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
#-dontobfuscate
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.proguard.annotations.DoNotStrip class *
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
@com.facebook.common.internal.DoNotStrip *;
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
void set*(***);
*** get*();
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { }
-keepclassmembers class *
{ @com.facebook.react.uimanager.UIP }
-keepclassmembers class *
{ @com.facebook.react.uimanager.annotations.ReactP }
-keepclassmembers class *
{ @com.facebook.react.uimanager.annotations.ReactPropG }
-dontwarn com.facebook.react.**
# TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
-dontwarn android.text.StaticLayout
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**
# Caused by: java.lang.NoSuchFieldError: no field with name='mHybridData'
-keep class com.facebook.** { *; }
#============================= React Native end =============================#
3.默认情况下,以上编译操作生成的aar文件中只包含armeabi-v7a和x86两种ABI下的so文件,如果运行时提示找不到so文件,那么可能就是你的abiFilter配置错了。但是如果你的应用的abiFilter只能配置为armeabi的话,可以考虑下面的做法:先解压aar文件,在jni目录下新建armeabi文件 夹,并将armeabi-v7a下面的so复制到armeabi中,然后删除x86和armeabi-v7a目录,最后重新压缩生成aar文件。
(2)对于iOS来说,项目中依赖的是11个RN Xcode子项目生成的静态库(.a)文件。
如何生成RN静态库呢?
这里可以通过react-native init命令创建一个新的RN demo项目,然后修改package.json文件,将RN版本调整为0.44.0版本,然后执行npm install,最后打开ios目录下的Xcode项目即可。
1.RN升级到0.44.0版本之后,Deployment Target要设置为8.0以上 (实际上从0.36版本的RN就需要做这个配置了)。
2.项目中除了要引入11个静态库文件,还需要引入RN相关的头文件,这些头文件可以在上面的demo项目的构建结果中找到,一般路径为/Users/[user]/Library/Developer/Xcode/DerivedData/[demo-project]/Build/Products/[Release-xxx]/include,引入之后别忘了添加到Header Search Path中。
3.一定要以release模式构建demo应用,否则生成静态库中RN环境实际上是dev环境,在手机摇晃的情况下会弹出RN的调试菜单!出现异常的还会显示RN的红屏界面!
4.生成静态库的时候要根据项目的配置来确定支持的平台,例如有可能项目需要的是同时支持armv7, arm64, i386, x86_64平台的静态库,那么这个时候就需要使用lipo命令,其中lipo -info命令可以查看一个静态库支持的平台,lipo -create命令可以将支持不同平台的静态库合并。
5.如果项目依赖高版本的RN静态库,可以正常加载低版本的RN打出来的bundle文件;反之,如果项目依赖的是低版本的RN静态库,那么加载高版本的RN打出来的bundle文件的时候会报错DeviceInfo native module is not installed correctly。
6.iOS端RN升级之后出现过cookie失效的问题,这个问题修改下JS端的代码,在请求的时候添加credentials。
2.关键路径日志补全,将RN源码内部重要日志定向到应用日志中
在应用输出的日志中补全关键路径的信息,例如bundle加载时使用的bundle文件位置、版本,bundle更新重载时使用的bundle文件位置、版本等。这里还做了个功能是将RN源码内部的重要日志定向到应用日志中,这样的话可以丰富应用日志的内容,方便在遇到问题的时候定位问题。
(1)对于Android来说,日志重定向功能是依靠FLog的setLoggingDelegate方法来实现的,只要实现自定义的LoggingDelegate就可以将RN源码端的日志定向到应用日志中
(2)对于iOS来说,日志重定向功能是依靠RCTAddLogFunction方法来实现的
3.重点流程耗时统计,关键事件数据上报
RN模块很容易出现问题,所以对它的重点流程的数据统计和上报也是非常重要的。例如bundle加载耗时多少,RN环境初始化耗时多少,bundle加载失败了多少次等等,这些数据都需要进行上报,以便后期提供更好的容错机制。
一般来说,大家都想知道的是bundle加载耗时多少、RN环境初始化耗时多少、RN界面渲染耗时多少这三个数据。
(1)对于Android来说,在RN的Android端源码中,ReactMarker会在很多重要事件的起始和结束设置标志,而ReactMarkerListener可以监听这些重要事件,所以如果我们设置了ReactMarkerListener的话,就能够在事件发生的时候收到回调从而统计耗时。
(2)对于iOS来说,在RN的iOS端源码中,RCTBridge的PerformanceLogger会在重要事件的起始和结束时设置tag并统计耗时,通过它可以直接取出各项事件的耗时数据。
4.完善bundle的更新时机,实现bundle立即生效方案
一般来说,为了方便和稳定,应用一般是在当次运行过程中下载好更新的bundle,但是在下次启动的时候才让新bundle生效。那如果想要实现在应用不重启的情况下让bundle当次立即生效怎么办呢?(需要注意的是,往往重新加载bundle文件的时候bundle文件位置可能不是原来那个位置)
(1)对于iOS来说,在RN的iOS端源码中RCTBridge提供了reload方法来重新加载bundle文件,还提供了setBundleURL方法来设置bundle文件的位置,所以iOS端RN离线包立即生效方案就是先设置新的bundle文件位置,然后再调用reload方法进行重载即可,不需要修改RN源码再重新编译。
(2)对于Android来说,RN的Android端源码并没有提供修改bundle文件位置的方法,所以这里修改了RN源码中的ReactInstanceManager类,删掉mBundleLoader变量的final修饰符,并为其提供set方法。和iOS端类似,RN离线包立即生效就是先根据新的bundle文件的位置设置ReactInstanceManager的JSBundlerLoader,然后调用recreateReactContextInBackground方法即可。
1.无论是Android端还是iOS端,bundle重载时最好要检查下当前屏幕是竖屏还是横屏,因为bundle重载的时候会重新加载和渲染之前已经attached的RN View(假设是按照横屏来布局的),如果bundle重载时手机是横屏,那么这个RN View会按照横屏进行布局,这样回来的时候界面就会显示异常了。
2.最好不要在应用当前处于RN界面的时候进行bundle重新加载,因为可能造成不可预计的数据异常或者界面显示异常,我们出现过一种数据异常导致应用crash的情况。
3.Android端的立即生效方案也许不是best practice,或许可以不修改源码就能够重新设置bundle位置,但是我目前没有细究,所以用了上面的方案。
5.Bundle文件加载容错机制
默认情况下我们发出去的app中自带一个稳定版本的bundle,在其他bundle加载失败的情况下,就使用app自带的bundle文件进行容错。目前Android端还没有做这个功能,iOS因为可以接收到bundle加载失败的通知所以实现了这个功能。
除了bundle文件加载容错机制外,一般还要在RN界面出现crash的时候降级到H5的容灾方案,这块目前还在计划开发中。因为要做到完整的容灾的话,可能需要能够拦截到RN模块大部分的异常,虽然RN源码提供了拦截方法,但是这只是其中的部分异常,还有不少异常情况并没有被拦截到。
6.给iOS端的RN开发阶段新增调试功能
众所周知,Android的RN调试菜单中可以指定server和port,这样就可以从network上加载指定的bundle文件,但是iOS的RN调试菜单中却没有这个功能,所以我实现了一个简易的针对iOS端开发阶段加载指定server上的bundle文件的调试功能,原理是利用RCTBundleURLProvider的jsBundleURLForBundleRoot:packagerHost:enableDev:enableMinification方法。
OK,可能花了一晚上只是写了一堆废话吧,谢谢你看完,如果内容有什么错误或者想咨询的可以通过邮件联系我,因为多说关闭了,本想着什么时候换成网易云跟帖,结果前段时间听说也要关闭了,所以我想算了吧,不想再去接入其他的评论系统了。博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)676被浏览96,488分享邀请回答687 条评论分享收藏感谢收起4914 条评论分享收藏感谢收起React-Native Component(580)
照例,我们先给出一个demo2-- secondRNapp的效果:
http://www.jianshu.com/p/4abdd42180b9
项目git地址:
Demo完成了利用Redux管理相对复杂的用户状态,同时使用了导航器Navigator来完成页面的跳转,并引入了一个带原生objective-C加载动画的第三方组件。
备注:样式上可以看出来,Ios这边适配的不错,但Android这边的适配还多多少少存在着一些坑,而且如果不经常使用flex这种类似百分比的布局的话,也很容易出现些细微的差别。
下面来看下项目目录:
首先我们发现入口文件中的代码少了很多,貌似是直接导入了src中的index.js来完成页面的展示。(作者和不少老司机推荐大家这样搞)。
再就是可以很明显的看出src中的目录复杂了。到这里能看懂的也就只有imgs--图片资源的目录和styles--项目提取出来的样式目录了,那么其他的目录下的文件都有什么作用呢?
现在就结合Demo讲下Redux和Navigator的使用方法和场景
(一)在react-native中使用Redux维护复杂的状态
1)Redux可以看成是一种Flux思想的实现,那么Flux思想又是什么呢?
Flux是Facebook用来构建用户端的Web应用程序的体系架构。
先来看传统的后台mvc框架,一个请求过来,Controller接收到了请求,然后根据请求,使用数据模型载入数据,再选择合适的视图展示上去;
而在前端,任意的一个事件都可以触发一次流程(事件等同于Action中的URL请求),而且还可能需要重复渲染新页面。另外很多View都可以自己接受事件、处理事件、更改样式,处理比较分散;而后端中的Action处理被集中在了Controller中进行。
那么是不是可以把前端中修改状态 即state 的行为(所有事件回调/Ajax等)全部抽象成一种Action描述,然后交付到一处即Reducers来进行原子化处理,然后Reducer修改整个应用中唯一的一棵state tree即Store,最后通过state-&view的机制来重新渲染?(这里面出现了很多新的词汇,先不着急懂,加个标签,看完Redux之后再回来重新看就明白了)
接下来就引入了Flux数据流框架:
①Action可以看成是修改Store的行为抽象;
②Dispatcher管理着应用的数据流,可以看为Action到Store的分发器;
③Store管理着整个应用的状态和逻辑,类似MVC中的Model。
2)下面就该正式介绍Redux了…
不同于Flux架构,Redux中没有dispatcher这个概念,并且Redux设想你永远不会变动你的数据,你应该在reducer中返回新的对象来作为应用的新状态。
但是它们都可以用(state,action) =&newState(这是reducer里的写法)来表述其核心思想,所以Redux可以被看成是Flux思想的一种实现,但是在细节上会有一些差异。
使用Redux的三个原则:
①Single source of truth
单一数据源。整个应用的state,存储在唯一一个object中,同时也只有一个store用于存储这个object.
② State is read-only
状态是只读的。唯一能改变state的方法,就是触发action操作。action是用来描述正在发生的事件的一个对象。
③Changes are made with pure functions
在改变state tree时,用到action,同时也需要编写对应的reducers才能完成state改变操作。
大体了解了Redux之后,再来看下本Demo的具体实例:
store用于维护状态的容器,包括了应用的多个状态(state集合),比如说用户是否登录、用户信息、用户任务等等。action是一个普通对象,用于指明是哪种操作,这样才能在reducers中进行识别。而众多reducer是负责返回新的state的函数。
在实际应用中,你需要将store或store的某个值绑定到界面,这样更新store的时候,该页面可以监听到值的更新,然后进行一些页面更新操作/跳转操作等。
在实际应用中,github上redux-*的第三方中间件、插件越来越多;
①比如用来实现异步的redux-thunk(一会在action中可以看到thunk定义写法的异步登陆请求):
同步只返回一个普通action对象。而异步操作中途会返回一个promise函数。当然在promise函数处理完毕后也会返回一个普通action对象。thunk中间件就是判断如果返回的是函数,则不传导给reducer,直到检测到是普通action对象,才交由reducer处理。
②用来将store对象存储到本地的redux-persist这个第三方插件,它还可以从本地恢复数据到store中,比如说保存登录信息,下次打开应用可以直接跳过登录界面。(功能gif中有体现,具体实现在Store中)
好了,说了这么多该来看看代码了,按着顺序来的话:
①第一步肯定是要创建一个全局的store了,
其中比较关键的就是把将要switch好多种返回状态的reducers全部import了进来,然后配置store的信息,运用redux-persist将store存储到本地,
在程序总入口(上面已经提到了,壳子入口中调用了该index.js)应用了store
②再来看action目录
types里面是各种用户的状态,
user里引入了types,然后模拟了两组假的用户数据(生产环境中可从网络获取),功能也比较简单。由于跳过和登出操作一般都只是单纯的设置或清空一些数据,不需要异步执行直接返回就可以了;而登陆操作属于耗时操作,所以需要异步执行,这里采用dispatch分发;
而有些人可能会问了,为啥会出来个dispatch方法,刚才不是说Redux里没有dispatch概念么?这个dispatch是引入了thunk异步第三方库后才出现的方法,你也看到了,同步的直接返回的确实没有用到dispatch~
③接下来看reducer
这个是个reducer的入口文件,就调了俩东西:一个是redux的组件,一个是调用的本文件夹下面写的那个。这里只是做了登陆的功能,所以只有userReducer,如果功能复杂的话,需要保存很多应用和用户交互产生的信息~
再来看看关键的部分:
看到了么,一个initialState初始状态,一个switch~
对每个传过来的action进行switch,每个action都需要返回一个state对象,如果不需要变动,则返回原对象(switch中的default返回值,千万别忘了default)。需要变动,则返回一个新的state,。
④redux的三部分至此就操作完毕,但如果进行链接起来呢
这里就用到connect组件,connect是将某一个组件(这里一般指一个页面)和store链接起来,目的就是获取当前页面所需的state以及dispatch方法。(从全局state中获取这个页面需要的数据然后以props的形式传递给当前页面。)
这是以其中一个页面login.js为例,进行的讲解,在最末尾的select中,指定了该组件会与store的哪些值进行连接。分别是isLoggedIn, user, status。
点击登录&Text&触发了handleLogin方法,里面判断当用户名和密码都不为空的时候,触发login这个action,然后将参数传过去,当做参数请求服务端。
备注:大家应该会注意到一个方法,shouldComponentUpdate,这个方法貌似不是自定义的,而且还没有人调用它,那么它在这做什么呢?又是什么时候执行呢?
这个方法的内容是控制加载的转圈圈的东西是否展示~调用就要讲到react native的生命周期了,之前的Demo1因为功能太简单,没有讲到生命周期,其实RN的组件同Android的activity组件一样,也是具有LifeCycle的
如图,可以把组件生命周期大致分为三个阶段:
·第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,在这里完成了组件的加载和初始化;有我们熟悉的render函数。还有getInitialState方法,之前是用来初始化state的,现在多在构造中完成
·第二阶段:是组件在运行和交互阶段,如图中左下角虚线框,这个阶段组件可以处理用户交互,或者接收事件更新界面;
这时候shouldComponentUpdate出现了,当组件接收到新的属性和状态改变的话,都会触发调用shouldComponentUpdate(...),函数原型如下:
booleanshouldComponentUpdate( object nextProps,object nextState)
输入参数nextProps和上面的componentWillReceiveProps函数一样,nextState表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果true表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。
默认情况下,这个函数永远返回true用来保证数据变化的时候UI能够同步更新。在大型项目中,你可以自己重载这个函数,通过检查变化前后属性和状态,来决定UI是否需要更新,能有效提高应用性能。
·第三阶段:是组件卸载消亡的阶段,如图中右下角的虚线框中,这里做一些组件的清理工作。
其他各生命周期的回调函数在这里就不详细介绍了,感兴趣的可以参看链接:
或官方文档
好了,生命周期讲完了,就可以理解当props和state发生了变化之后,进行的一系列函数的调用。
最后再串一下顺序:
①首先我们创建全局的store(基于所有的reducer)在APP最外层引用,然后我们创建action(可以根据页面或者某种类别来定义)。接着我们创建reducer(可以设计成跟action一一对应,例如user)。最后通过connect将它们和页面链接起来,至于action和reducer的内容,可以等页面编辑OK后再进行设计。
②执行简单流程:在页面中首先调用对应action方法(传递参数)---&执行相应的业务逻辑,然后调用dispatch(action)(将结果以action的形式传递给reducer)---&在reducer中根据type字段然后返回最新的state,然后再进行render具体的ui更新。
(二)Navigator控制页面跳转
移动应用很少只包含一个页面。从你添加第二个页面开始,就得考虑如何管理多个页面间的跳转了。导航器正是为此而生。它可以管理多个页面间的跳转,也包含了一些常见的过渡动画,包括水平翻页、垂直弹出等等。
要讲导航器首先要理解场景(Scene)的概念:
场景简单来说其实就是一个全屏的React组件。与之相对的是单个的Text、Image又或者是你自定义的什么组件,仅仅占据页面中的一部分。
使用Navigator进行页面跳转首先就是要渲染一个Navigator组件,Navigator组件中有一个重要的概念(Route路由)和两个关键的方法initialRoute与renderScene;
本项目中,总入口处可以发现,页面的内容是通过组件&Root/&实现的
那么我们就通过&Root&中的内容来介绍这一个概念和两个方法,可以直接从render方法看,:
①initialRoute: 这个是有个初始化的页面,就是默认的页面,这里的参数都是自己自定义的(反正是自己发自己收); name只是一个名字,而page,这里叫page,别的地方叫component,这个是最关键的, 真正有用的是component,别的没啥用
②renderScene: 这个方法是完全根据路由提供的信息来渲染场景的。你可以在路由中任意自定义参数以区分标记不同的场景。本Demo中传入了两个参数,第一个参数就是场景信息,第二个参数是navigator对象,要过渡到新的场景,你需要了解push和pop方法。这两个方法由navigator对象提供,我们使用这两个方法来把路由对象推入或弹出导航栈。
renderScene方法必须要return一个react组件,createElement的第一个参数就是一个react class;本demo中则是添加了第二个参数,这第二个参数则是一些额外的参数,可以在跳转到的场景中获取到~
③路由的概念:“路由”抽象自现实生活中的路牌,在RN中专指包含了场景信息的对象;renderScene方法中的第一个参数,如果传入的是“route”的话,那么这个route对象就包含着一开始定义的name和page属性,所以,initialRoute和renderScene的第一个参数,都是一个“路牌”的作用
在root.js的最后,还是用了connect绑定了isLoggedIn这个属性,在这里配合构造中的判断,来完成一开始介绍的那个取出本地保存的登陆状态,跳转对应页面的功能。
备注:细心的同学可能又发现了,还有一个configureScene方法没有介绍,而且,貌似navigator对象也被当成了一个参数传给了一个新的类Router();况且我们还有一个configs目录一直没有介绍。这个目录里就放着我们的Router类和一个sceneConfig配置
①Router类在创建的时候,传入了一个navigator方法,前面说过navigator方法中有push和pop的方法,但其实还有一些别的方法,如:popToTop(Pop to the first scene in the stack)、resetTo()等。Router就是在这些方法之上又封装了一些自定义的方法,使用起来会更加的方便,这种编程的方法比较适合学习,如
它们被当成参数传给了Login.js和Main.js页面,能够调的到。
②configureScene这个函数是控制场景跳转的动画的,sceneConfig里面是一些自定义的动画效果。
备注:听晕了的同学可以去看下
新手理解Navigator,那个例子比这个简单的多,更方便理解~
(三)引入带原生的objective-C加载动画的第三方组件
如果大家是比着敲而不是直接拷贝我的项目去运行的,那么有可能会遇到一个问题:
为啥那个loading的加载圈圈,样式出不来,一直是一个巨丑的方框?这里就要注意了,一些第三方控件一定要重新link,这样才可以看到样式,不然完犊子,比如这个react-native-spinkit;
本demo中的Login和Main两个页面中都引用了些git上的样式如下:
看出来了吧,spinkit是个objective-C的~
之前纯JS的组件的导入方式我们已经讲过了,那接下来,这种Objective-C的该怎么搞呢?
Git上虽然有讲,但我们也在这里讲一下把:
①首先也是要先 npm installreact-native-spinkit --save把它加到package.json中
②然后可以用Git上提供的Link命令外加一系列操作,链接上IOS native;也可以直接使用RNPM命令
在这里我推荐使用rnpm命令,虽然本demo中的spinkit没法在Android上使用,但是rnpm会帮你把ios和Android的都给连接上,不用单独去处理
使用npm install rnpm -g命令,把rnpm安装成全局变量
然后执行rnpm link react-native-spinkit
然后就可以看到命令行提示成功链接了!!!!
备注:如果成功链接之后,JS代码是直接刷新页面,reloadJs就可以使用了;而与原生相关的组件,就需要重新去编译IOS的代码了,让IOS的壳子重新运行!!!才可以调用组件,成功看到效果
好了,Demo2终于讲完了,还是,代码下下来仔细看看注释,我的注释打的都是傻瓜式的,非常详细,很适合新手阅读并配合文档理解。}

我要回帖

更多关于 战狼2为啥火得不像话 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信