native react 拨号_react native拨号 - CSDN
  • react-native 拨打电话

    2019-05-07 14:32:33
    import React, { PureComponent } from 'react'; import { Text, TouchableOpacity, Linking, Alert } from 'react-native'; import { Toast } from '@ant-design/react-native'; class Contact extends PureCompo....
    import React, { PureComponent } from 'react';
    import { Text, TouchableOpacity, Linking, Alert } from 'react-native';
    import { Toast } from '@ant-design/react-native';
    
    class Contact extends PureComponent {
      /**
       *  拨打电话
       * @param {string} phone 版本号
       * @example
       * call('18888888888')
       */
      call = phone => {
        const url = `tel:${phone}`;
        Linking.canOpenURL(url)
          .then(supported => {
            if (!supported) {
              return Alert.alert('提示', `您的设备不支持该功能,请手动拨打 ${phone}`, [
                { text: '确定' }
              ]);
            }
            return Linking.openURL(url);
          })
          .catch(err => Toast.info(`出错了:${err}`, 1.5));
      };
    
      callMerchant = () => {
        this.call('18888888888');
      };
    
      render() {
        return (
          <TouchableOpacity onPress={this.callMerchant}>
            <Text>联系商家</Text>
          </TouchableOpacity>
        );
      }
    }
    
    export default Contact;
    

     

    展开全文
  • 欢迎大家关注【跨平台开发那些事】公众号,定期推送跨平台开发技术实践。 在前两篇的内容中,和大家分享了Android原生集成RN,以及RN的增量热更新。...本篇内容同样和React Native 与 原生App有关,可...

     

    欢迎大家关注【跨平台开发那些事】公众号,定期推送跨平台开发技术实践。

     

    在前两篇的内容中,和大家分享了Android原生集成RN,以及RN的增量热更新。关于详细的内容,点击如下具体了解:

      Android App巧妙集成React Native最详教程

      React Native 实现热部署、增量热更新

     

    本篇内容同样和React Native 与 原生App有关,可以说更加深入了两者之间的感情,为培养下一代做出准备:React Native与原生App的通信交互。

    Android系统为我们提供了webview来加载网页,为了让webview加载的网页可以与App交互,系统提供了一套机制帮助我们更方便的实现通信。同样为了实现React Native与原生App之间的通信,FB也实现了自己的一套交互机制。

    (1)RCTDeviceEventEmitter 事件方式

    (2)Callback 回调方式

    (3)Promise

    (4)直传常量数据(原生向RN)

    三种方式各具不同优缺点

    1. RCTDeviceEventEmitter

       优点:可任意时刻传递,Native主导控制。

    2. Callback

       优点:JS调用,Native返回。

       缺点:CallBack为异步操作,返回时机不确定

    3. Promise

     

       优点:JS调用,Native返回。

       缺点:每次使用需要JS调用一次

    了解了三者的通信方式,怎么能少了代码的描述!我们来看看代码如何实现。大致的实现步骤如下:

    (1)定义Module类,继承ReactContextBaseJavaModule

             在Module类中,我们定义交互的方法,例如RN调用Native的方法,Native调用RN的方法等。

    (2)定义Package类,继承ReactPackage

             实现Package的createNativeModules方法,将Module实例添加到集合。

    (3)定义Application,继承ReactApplication

             实现getPackages方法,将Package实例添加到getPackages下的集合。

    4. 直传常量数据(原生向RN)

             跨域传值,只能从原生端向RN端传递。RN端可通过 NativeModules.[module名].[参数名] 的方式获取

    1.Module类中的核心代码

     

        /**
         * 在rn代码里面是需要这个名字来调用该类的方法
         * @return
         */
        @Override
        public String getName() {
            return MODULE_NAME;
        }

     

     名称可以自定义,对接时协商好即可。

     

        /**
         * RN调用Native的方法
         * @param phone
         */
        @ReactMethod
        public void rnCallNative(String phone) {
    
            // 跳转到打电话界面
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:" + phone));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 跳转需要添加flag, 否则报错
            mContext.startActivity(intent);
        }

     

      在module中定义一个方法,并用@ReactMethod 注解标注:表明该方法会被RN调用。即被RN调用的原生方法必须使用@ReactMethod注解标注。

      注意:RN层调用Native层进行界面跳转时,需要设置FLAG_ACTIVITY_NEW_TASK标志,否则会出现如下错误:

     

     

        /**
         * Native调用RN
         * @param msg
         */
        public void nativeCallRn(String msg) {
            mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                    .emit(EVENT_NAME,msg);
        }

     

      上面代码定义了原生方法,通过在Android层调用RN层。使用ReactContext的getJSModule方法,emit来发送消息。同样,emit的第一个参数要与RN层中addListener方法的第一个参数相同。

    2.自定义Package的核心代码

     

    /**
     * 通信Package类
     * Created by Song on 2017/2/17.
     */
    public class CommPackage implements ReactPackage {
    
        public CommModule mModule;
    
        /**
         * 创建Native Module
         * @param reactContext
         * @return
         */
        @Override
        public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
            List<NativeModule> modules = new ArrayList<>();
            mModule = new CommModule(reactContext);
            modules.add(mModule);
            return modules;
        }
    
        @Override
        public List<Class<? extends JavaScriptModule>> createJSModules() {
            return Collections.emptyList();
        }
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    }

     在createNativeModules方法中,初始化集合,并将module实例添加进集合,返回集合实例。

    3.Application核心代码

     

       private static final CommPackage mCommPackage = new CommPackage();
       /**
         * 获取 reactPackage
         * @return
         */
        public static CommPackage getReactPackage() {
            return mCommPackage;
        }

    在getPackages方法中,将Package实例添加到Arrays中即可完成注册。以上就是Android层核心代码配置,继续来看React Native层核心代码:

    1.调用原生代码

       /**
        * 调用原生代码
        */
        skipNativeCall() {
           let phone = '18637070949';
           NativeModules.commModule.rnCallNative(phone);
        }

    在React Native层,通过NativeModules调用commModule,继而调用原生方法即可。注意:commModule要与Module类的getNames方法返回的名称对应。

    2. 接收原生调用

       /**
        * 接收原生调用
        */
       componentDidMount() {
           DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{
                title = "React Native界面,收到数据:" + msg;
                ToastAndroid.show("发送成功", ToastAndroid.SHORT);
           })
       }

    通过DeviceEventEmitter注册监听,类似于Android中的监听事件。第一个参数标识名称,要与Module中emit的Event Name相同。第二个参数即为处理回掉。

    3.界面代码

     render() {
        return (
          <View style={styles.container}>
            <Text style={styles.welcome} >
                {title}
            </Text>
             <Text style={styles.welcome} onPress={this.skipNativeCall.bind(this)}>
                跳转到拨号界面
             </Text>
            
             <Image source={require('./images/ic.png')} />
          </View>
        );
      }

    在Text中注册单击事件,RN层调用原生代码,跳转到拨号界面。

    4.Android层调用RN的代码

        /**
         * 向RN发送消息
         * @param v
         */
        public void sendMsgToRN(View v) {
            Log.e("---","sendMsgToRN");
            MainApplication.getReactPackage().mModule.nativeCallRn("hello");
        }

    调用Module中定义的nativeCallRn方法,继而出发RN层代码。以上就是通过 RCTDeviceEventEmitter 模式进行通信交互。可以很清晰的看出,交互都是以主动方式为主。

    RN中剩下的两种通信方式,存在一个共同的特点:

    从RN层调用Native层,Native层处理完成后,回调RN层

    直接看代码实现:

    (1)Callback

    同样还是在Module类中定义交互方法:

        /**
         * Callback 方式
         * rn调用Native,并获取返回值
         * @param msg
         * @param callback
         */
        @ReactMethod
        public void rnCallNativeFromCallback(String msg, Callback callback) {
    
            // 1.处理业务逻辑...
            String result = "处理结果:" + msg;
            // 2.回调RN,即将处理结果返回给RN
            callback.invoke(result);
        }

    RN中定义回调:

       /**
        * Callback 通信方式
        */
        callbackComm(msg) {
            NativeModules.commModule.rnCallNativeFromCallback(msg,(result) => {
                 ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT);
            })
        }

    (2)Promise

    Module类中定义交互方法:

        /**
         * Promise 方式
         * @param msg
         * @param promise
         */
        @ReactMethod
        public void rnCallNativeFromPromise(String msg, Promise promise) {
    
            Log.e("---","adasdasda");
            // 1.处理业务逻辑...
            String result = "处理结果:" + msg;
            // 2.回调RN,即将处理结果返回给RN
            promise.resolve(result);
        }

     RN中定义回调:

        /**
         * Promise 通信方式
         */
        promiseComm(msg) {
            NativeModules.commModule.rnCallNativeFromPromise(msg).then(
                (result) =>{
                    ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT)
                }
            ).catch((error) =>{console.log(error)});
        }

    布局中触发单击事件:

     <Text style={styles.welcome} onPress={this.skipNativeCall.bind(this)}>
                跳转到拨号界面
             </Text>
             <Text style={styles.welcome} onPress={this.callbackComm.bind(this,'callback发送啦')}>
                Callback通信方式
             </Text>
             <Text style={styles.welcome} onPress={this.promiseComm.bind(this,'promise发送啦')}>
                Promise通信方式
             </Text>

    (3)直传常量数据(原生向RN)

    自定义Module类中实现getConstants方法

     

        @Nullable
        @Override
        public Map<String, Object> getConstants() {
            return super.getConstants();
        }

    以上是默认实现,getConstants方法中调用了super.getConstants(),跟踪源码可以看到

     

     

      /**
       * @return a map of constants this module exports to JS. Supports JSON types.
       */
      public @Nullable Map<String, Object> getConstants() {
        return null;
      }

    从源码注释中可以看出,该方法是返回一个Map类型的常量,导出到JS端(即RN)。支持JSON 类型。所以,我们只需要重写方法,声明Map集合,向其中添加常量后,返回即可。所以就有了如下代码

     

     

        @Nullable
        @Override
        public Map<String, Object> getConstants() {
            Map<String,Object> params = new HashMap<>();
            params.put("Constant","我是常量,传递给RN");
            return params;
        }

    此时,在RN端,我们可以通过NativeModules来接收即可

     

     

    componentWillMount() {
    	let result = NativeModules.MyModule.Constant
    }

     

     

     

     

     

     

     

    最终效果:

      Android调用React Native:

     

      React Native调用Android:

     

     

      源码以上传到github,希望大家star,follow支持哦~

      源码下载

    展开全文
  • Native、Web App、Hybrid、React Native(后面以RN简称)、Weex 间的异同点,后期同步小程序 和 PWA。 App常用开发模式简介 此处App为应用,application,并非我们通常讲的手机App。 常用的几种APP开发模式-脑图...

    一句话概要

    Native、Web App、Hybrid、React Native(后面以RN简称)、Weex 间的异同点,后期同步小程序 和 PWA。

    App常用开发模式简介

    此处App为应用,application,并非我们通常讲的手机App。

    常用的几种APP开发模式-脑图:http://naotu.baidu.com/file/6af15fcbb72f89926043779811b1ea44?token=df0378691ecdcef2

    Native App

    传统的原生App开发模式,有iOS和aOS两大系统,需要各自语言开发各自App。

    优点:性能和体验都是最好的。

    缺点:开发和发布成本高。

    举个栗子:网易管家App (https://id.163.com/gj/)

    应用技术:Swift,OC,Java。

    WebApp

    移动端的网站,常被称为H5应用,说白了就是特定运行在移动端浏览器上的网站应用。一般泛指 SPA(Single Page Application)模式开发出的网站,与MPA(Multi-page Application)对应。

    优点:开发和发布成本最低。

    缺点:性能和体验不能讲是最差的,但也受到浏览器处理能力的限制,多次下载同样会占用用户一定的流量。

    举个栗子:网易管家APP(https://id.163.com/gj/)

    应用技术:ReactJS,RegularJS,VueJS等等。

    Hybrid App

    混合模式移动应用,介于Web App、Native App这两者之间的App开发技术,兼具“Native App良好交互体验的优势”和“Web App跨平台开发的优势”(百度百科解释)

    主要的原理是,由Native通过JSBridge等方法提供统一的API,然后用Html+Css实现界面,JS来写逻辑,调用API,最终的页面在Webview中显示,这种模式下,Android、iOS的API一般有一致性,Hybrid App所以有跨平台效果。

    优点:开发和发布都比较方便,效率介于Native App、Web App之间。

    缺点:学习范围较广,需要原生配合。

    举个栗子:FanReact,我爱我家App,东方航空App,富国基金-富国钱包App

    应用技术:PhoneGap,AppCan,Wex5,APICloud等。

    React Native App

    Facebook发现Hybrid App存在很多缺陷和不足,于是发起开源的一套新的App开发方案RN。使用JSX语言写原生界面,js通过JSBridge调用原生API渲染UI交互通信。

    优点:效率体验接近Native App,发布和开发成本低于Native App。

    缺点:学习有一定成本,且文档较少,免不了踩坑。

    举个栗子:Facebook、Youtube、Discord、QQ、百度等等。

    Weex App

    阿里巴巴开发团队在RN的成功案例上,重新设计出的一套开发模式,站在了巨人肩膀上并有淘宝团队项目做养料,广受关注,2016年4月正式开源,并在v2.0版本官方支持Vue.js,与RN分庭抗礼。

    优点:单页开发模式效率极高,热更新发包体积小,并且跨平台性更强。

    缺点:刚刚起步,文档欠缺;社区没有RN活跃,功能尚不健全,暂不适合完全使用Weex开发App。

    举个栗子:淘宝、天猫、阿里云、优酷、闲鱼、饿了么等。

    Native App

    Native App是一种基于智能手机本地操作系统如iOS、Android、WP并使用原生程式编写运行的第三方应用程序,也叫本地app。一般使用的开发语言为Java、C++、Objective-C。

    自iOS和Android这两个的手机操作系统发布以来,在互联网界从此就多了一个新的名词:App意为运行在智能的移动终端设备第三方应用程序。

    Native App因为位于平台层上方,向下访问和兼容的能力会比较好一些,可以支持在线或离线,消息推送或本地资源访问,摄像拨号功能的调取。但是由于设备碎片化,App的开发成本要高很多,维持多个版本的更新升级比较麻烦,用户的安装门槛也比较高。但是比较乐观的是,AppStore培养了一种比较好的用户付费模式,所以在Apple的生态圈里,开发者的盈利模式是一种明朗状态,其他market也在往这条路上靠拢。

    优势

     

    • 相比于其它模式,提供最佳的用户体验,最优质的用户界面,最华丽的交互

    • 针对不同平台提供不同体验

    • 可节省带宽成本,打开速度更快

    • 功能最为强大,特别是在与系统交互中,几乎所有功能都能实现

     

    劣势

     

    • 门槛高,原生开发人才稀缺,至少比前端和后端少,开发环境昂贵

    • 无法跨平台,开发的成本比较大,各个系统独立开发

    • 发布成本高,需要通过store或market的审核,导致更新缓慢

    • 维持多个版本、多个系统的成本比较高,而且必须做兼容

    • 应用市场逐渐饱和,怎么样抢占用户时间需要投入大量时间和金钱,这也导致“僵尸”App的增多

     

    WebApp

    说到Web App 不少人会联想到 WAP,或者有人认为,WAP就是WebApp,其实不然。

    WebApp 与 WAP 最直接的区别就是功能层面。WAP更侧重使用网页技术在移动端做展示,包括文字、媒体文件等。而Web App更侧重“功能”,是使用网页技术实现的App。总的来说,Web App就是运行于网络和标准浏览器上,基于网页技术开发实现特定功能的应用。

    响应式的大部分技术都是为实现WebApp能适配多类客户端而设计的。

    Web网站一般分两种,MPA(Multi-page Application)和SPA(Single-page Application)。而WebApp一般泛指SPA形式开发出的网站。这样更像是一个App。

    优势

     

    • 可以跨平台,调试方便

    • 无需安装,不会占用手机内存,而且更新速度最快

    • 不存在多版本问题,维护成本低

    • 临时入口,可以随意嵌入

     

    劣势

     

    • 依赖于网络,第一次访问页面速度慢,耗费流量

    • 受限于手机和浏览器性能,用户体验相较于其他模式最差

    • 功能受限,大量移动端功能无法实现

    • 入口强依赖于第三方浏览器,且只能以URL地址的形式存在,导致用户留存率低(优点即缺点)

     

    Hybird App

    混合开发,也就是半原生半Web的开发模式,由原生提供统一的API给JS调用,实际的主要逻辑有Html和JS来完成,最终是放在webview中显示的,所以只需要写一套代码即可达到跨平台效果,另外也可以直接在浏览器中调试,很方便。最重要的是只需要一个前端人员稍微学习下JS api的调用即可。

    Hybird App 的较早实践者是PhoneGap,随后遍地开花,如Titanium、Salama、WeX5、Kerkee和国内的AppCan,项目各有各的实现方式,大致的原理基本相同。有幸在AppCan上海总部参与过一段时间的学习研究,如下大致简介:

    AppCan是基于HTML5技术的Hybird跨平台移动应用开发工具。开发者利用Html5+Css3+JavaScript技术,通过AppCan IDE集成开发系统、云端打包器等,快速开发出Android、iOS、WP平台上的移动应用。

    AppCan的平台构成:

    在实际的APP开发中,AppCan可以完成大部分的工作量,如图示:

    AppCan将App底层复杂的原生功能封装在引擎、插件中,开发者仅需调用接口、打包编译,就可以获得原生功能;灵活的插件扩展机制。

    开发者可以像开发WebApp一样开发app的视觉UI,以及绝大部分的交互,当需要使用原生功能(如摄像头,陀螺仪等功能)时,只需要调用官方的API就可以轻松实现Native的效果。至于JS和Native的通信,常用的有URL监听和绝大部分Hybrid厂商使用的JSBridge通信,两者原理相近。

    关于JsBridge的原理详解,可见http://blog.csdn.net/xiangzhihong8/article/details/66970600

    在Hybird概念盛行的时候,国内外各大公司也参与了探索,国外代表有Facebook、google、亚马逊,国内的有腾讯、阿里巴巴、网易等,慢慢的他们发现Hybird严重受限于WebView的解析渲染效率,于是Facebook开始了他的类原生的研究探索。

    React Native App

    请移驾:【笔记】React Native 快速入门笔记(https://segmentfault.com/a/1190000010989345)。

    Weex App

    请移驾:网易严选App感受Weex开发(https://segmentfault.com/a/1190000011027225)。

     

    编辑:千锋HTML5

    来源:zwwill_木羽

    展开全文
  • Linking提供了一个通用的接口来与传入和传出的App链接进行交互,...下面写个简单的打电话例子,仅供参考import React, { Component} from 'react'; import {Slider, ListView,Linking, Text,ScrollView, View, Switch,T

    Linking提供了一个通用的接口来与传入和传出的App链接进行交互,我介绍的Linking的传出,比如跳转外部链接,打电话,发邮件,打开某个浏览器链接。

    下面写个简单的打电话例子,仅供参考

    import React, { Component} from 'react';
    import {Slider, ListView,Linking, Text,ScrollView, View, Switch,TouchableOpacity,Dimensions, StyleSheet, Alert, Platform, Image,TextInput,Clipboard,boolean} from "react-native";
    import Commons,{Link,RefreshListView, RefreshScrollView} from 'commons';
    import Apis, {TalentUserBase} from "app-js-sdk";
    
    export default class ContactTalentScreen extends Component {
        commons: Commons = new Commons().bind(this);
    
        constructor(props) {
            super(props);
        }
    
        static navigatorStyle = {
            navBarHidden: true,
            tabBarHidden:true,
        };
    
        state = {
            parentTalentUser:TalentUserBase,
        };
    
        componentDidMount() {
            this.commons.apis.userApi.getTalentUser().then((m:TalentUserBase)=>{
                this.setState({
                    parentTalentUser:m,
                });
            })
        }
    
        clearClose = ()=>{
            //关闭弹框
            this.props.navigator.dismissLightBox();
        }
    
    
        //拨打电话
       linking=(url)=>{
    
           console.log(url);
    
           Linking.canOpenURL(url).then(supported => {
               if (!supported) {
                   console.log('Can\'t handle url: ' + url);
               } else {
                   return Linking.openURL(url);
               }
           }).catch(err => console.error('An error occurred', err));
    
        }
    
       //复制手机号
        async _setClipboardContent(tel){
    
            Clipboard.setString(tel);
            try {
                var content = await Clipboard.getString();
                console.log('复制的手机号:');
                this.clearClose();
                console.log(content);
                //ToastAndroid.show('粘贴板的内容为:'+content,ToastAndroid.SHORT);
            } catch (e) {
                //ToastAndroid.show(e.message,ToastAndroid.SHORT);
            }
        }
    
        render() {
            const {height, width} = Dimensions.get('window');
            return (
                <View style={[styles.wrap,{width:width,height:height}]}>
                    <View style={[styles.pop,{width:width}]}>
                        <View style={styles.item}>
                            <Text style={styles.user_name}>{this.state.parentTalentUser.realname} {this.state.parentTalentUser.tel} 你可以</Text>
                        </View>
                        <View style={styles.solid}></View>
                        <View style={styles.bg_white}>
                            <TouchableOpacity style={styles.item} activeOpacity={0.5}  onPress={()=>this.linking('tel:'+this.state.parentTalentUser.tel)}>
                                <Text style={styles.title}>呼叫</Text>
                            </TouchableOpacity>
                        </View>
                        <View style={styles.solid}></View>
                        <View style={styles.bg_white}>
                            <TouchableOpacity style={styles.item} activeOpacity={0.5} onPress={()=>this._setClipboardContent(this.state.parentTalentUser.tel)}>
                                <Text style={styles.title}>复制号码</Text>
                            </TouchableOpacity>
                        </View>
    
                        <View style={styles.h9}></View>
                        <View style={styles.bg_white}>
                            <TouchableOpacity style={styles.item} activeOpacity={0.5}  onPress={()=>this.clearClose()}>
                                <Text style={styles.title}>取消</Text>
                            </TouchableOpacity>
                        </View>
                    </View>
                </View>
            );
        }
    
    }
    
    const styles = StyleSheet.create({
        wrap:{
    
        },
        pop:{
            position:'absolute',
            bottom:0,
            left:0,
            zIndex:100,
        },
        item:{
            flexDirection: 'row',
            height:50,
            justifyContent:'center',
            alignItems:'center',
            backgroundColor:'#fff',
            paddingLeft:15,
            paddingRight:15,
        },
        title:{
            fontSize:15,
            color:'#333',
        },
        user_name:{
            fontSize:12,
            color:'#888'
        },
        h9:{
            height:9,
            backgroundColor:'#f0f0f0',
        },
        solid:{
            height:0.5,
            backgroundColor:'#f0f0f0',
        },
        bg_white:{
            backgroundColor:'#fff',
        },
    });

    1.要启动一个链接相对应的应用(打开浏览器、邮箱或者其它的应用),只需调用

    Linking.openURL(url).catch(err => console.error('An error occurred', err));


    2.如果要在打开之前判断是否安装了相应的应用,调用:

    Linking.canOpenURL(url).then(supported => {
      if (!supported) {
        console.log('Can\'t handle url: ' + url);
      } else {
        return Linking.openURL(url);
      }
    }).catch(err => console.error('An error occurred', err));

    这里的url参数可以是其他类型的,比如一个地理位置(形如"geo:37.484847,-122.148386"或是一个通讯录名片,只要是可以通过{@code Intent.ACTION_VIEW}打开的即可。


    注:对于web链接来说,协议头("http://", "https://")不能省略!













    展开全文
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
    #0、手把手教React Native实战之开山篇
    
    ##作者简介
    
      东方耀    Android开发
      RN技术   facebook
      github  
      android ios  原生开发
      react reactjs nodejs 前端  进入 移动互联网 
      js nodejs    大波
      app 
      个人角度   学习的必要性    全栈工程师的捷径
    
      公司角度    组件化  成本降低  热更新 
    
    <font color=red size=5>加作者微信公众号(dongfangyao888)或扫描下面二维码</font>
    
    <font color=red size=6>推送高清视频教程+语音解说+课堂笔记和源码</font>
    
    ![微信号:dongfangyao888二维码](http://image17-c.poco.cn/mypoco/myphoto/20160309/23/17351665220160309234005020.jpg?430x430_120) 
    
    
    ##技术背景
       
       app store 
       facebook   html5   native app 
       Hybrid app   native +  web   混合模式 
       
    
    ##视频课程简介
    
    1.基础语法
    
    2.API和组件
    
    3.App更新 热更新上架
    
    4.实战项目  3个  RN技术开发 
    
    ##0、配套视频(下载地址):https://yunpan.cn/cY4JWzTtmVyNY  访问密码 7b60 或 http://vdisk.weibo.com/s/aLDC43gEH4wZV
    
    
    #36、手把手教React Native实战之API学习AppRegistry
    
    只有配合使用React Native的常用组件和常用API,才能更好的开发应用程序
    
    AppRegistry是JS运行所有React Native应用的入口。应用的根组件应当通过AppRegistry.registerComponent方法注册自己,当注册完后,原生系统才可以加载应用的bundle包并且触发AppRegistry.runApplication来真正运行应用。
    
    
    ##36、配套视频(下载地址):https://yunpan.cn/cRQVAkkrfVKDx  访问密码 40dc
    
    
    #37、手把手教React Native实战之API学习AsyncStorage
    
    AsyncStorage是一个简单的、具有异步特性的键值对的存储系统,全局的!替代LocalStorage
    
    AsyncStorage里面都有一个回调函数,而回调的第一个参数都是错误对象,如果发生错误,该对象就会展示错误信息,否则为null;每个方法都会返回一个Promise对象。
    
    案例:购物车(数据共享)
    
    列表页 结算页
    
    1.数据模型构建
    
    2.列表项Item组件(es6中默认属性与属性类型的定义)
    
    3.列表组件List
    
    guid代码 生成
    
    4.购物车组件
    
    去取AsyncStorage中存储的数据,一定是在DidMount生命周期里,不能在WillMount里
    
    5.将组件串联起来
    
    推荐由React Native中文网封装维护的react-native-storage模块,提供了较多便利功能。
    
    
    ##37、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=39&extra=page%3D1
    
    #38、手把手教React Native实战之物理back键详解
    
    在上一节课代码的基础上:
    
    componentWillMount() {
        if (Platform.OS === 'android') {
          BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);
        }
      }
      componentWillUnmount() {
        if (Platform.OS === 'android') {
          BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);
        }
      }
    
     onBackAndroid = () => {
            const { navigator } = this.props;
            const routers = navigator.getCurrentRoutes();
            console.log('当前路由长度:'+routers.length);
            if (routers.length > 1) {
                navigator.pop();
                return true;//接管默认行为
            }
            return false;//默认行为
    
        };
    
    说明:BackAndroid在iOS平台下是一个空实现,所以理论上不做这个Platform.OS === 'android'判断也是安全的。
    如果所有事件监听函数中,没有任何一个返回真值,就会默认调用默认行为
    
    navigator是同一个,这个事件在最外层注册就行(不是initialRoute的组件,是AppRegistry的组件),
    否则会调用多次pop的,这个代码接管的是整个应用的后退键
    
    放到initialRoute里会有问题,你两三个页面测不出来,页面层次多了组件会unmount,然后事件就丢了
    
    addEventListener()第三个参数useCapture (Boolean)详细解析:
    •true 的触发顺序总是在 false 之前;
    
    •如果多个均为 true,则外层的触发先于内层;
    
    •如果多个均为 false,则内层的触发先于外层。
    
    
    需要注意的是,不论是bind还是箭头函数,
    每次被执行都返回的是一个新的函数引用,
    因此如果你还需要函数的引用去做一些别的事情(譬如卸载监听器),那么你必须自己保存这个引用
    
    
    // 错误的做法
    class PauseMenu extends React.Component{
        componentWillMount(){
            AppStateIOS.addEventListener('change', this.onAppPaused.bind(this));
        }
        componentDidUnmount(){
            AppStateIOS.removeEventListener('change', this.onAppPaused.bind(this));
        }
        onAppPaused(event){
        }
    }
    // 正确的做法1
    class PauseMenu extends React.Component{
        constructor(props){
            super(props);
            this._onAppPaused = this.onAppPaused.bind(this);
        }
        componentWillMount(){
            AppStateIOS.addEventListener('change', this._onAppPaused);
        }
        componentDidUnmount(){
            AppStateIOS.removeEventListener('change', this._onAppPaused);
        }
        onAppPaused(event){
        }
    }
    
    
    // 正确的做法2
    class PauseMenu extends React.Component{
        componentWillMount(){
            AppStateIOS.addEventListener('change', this.onAppPaused);
        }
        componentDidUnmount(){
            AppStateIOS.removeEventListener('change', this.onAppPaused);
        }
        onAppPaused = (event) => {
            //把方法直接作为一个arrow function的属性来定义,初始化的时候就绑定好了this指针
        }
    }
    
    
    例子:“再按一次退出应用”
    //到了主页了
          if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
            //最近2秒内按过back键,可以退出应用。
            return false;
          }
          this.lastBackPressed = Date.now();
          ToastAndroid.show('再按一次退出应用',ToastAndroid.SHORT);
          return true;
          
          
    我们在监听函数中不能决定是否要调用默认行为,要等待一个异步操作之后才调用默认行为,此时可以通过第二种办法:
    
    使用BackAndroid.exitApp()来退出应用。
    
    例子:在退出应用之前保存数据
    
    写法1:
     onBackAndroid = () =>{
        saveData().then(()=>{
          BackAndroid.exitApp();
        });
        return true;
      }
      
      在监听函数中,我们开始异步事件,并直接return true。此时默认行为不会被调用。当保存完毕后,我们调用exitApp(),触发默认行为,退出应用。
      
      写法2:
       onBackAndroid = async () =>{
        await saveData();
        BackAndroid.exitApp();
      }
      
      这里我们用了async函数,async 函数总是返回一个Promise,Promise作为一个对象,也被认为是一个“真值”,所以这种情况下默认行为总是不会被调用。当保存完毕后,我们调用exitApp(),触发默认行为,退出应用。
      
      根据当前界面决定作何动作
      有时候我们有这样的需求:当用户处于某些界面下时,back键要做特殊的动作,如:提示用户是否要保存数据,或者解锁界面禁止back键返回等等。此时,最佳实践是在route或route中对应的Component上保存关于如何处理back键的信息:
      onBackAndroid = () => {
        const nav = this.navigator;
        const routers = nav.getCurrentRoutes();
        if (routers.length > 1) {
          const top = routers[routers.length - 1];
          if (top.ignoreBack || top.component.ignoreBack){
            // 路由或组件上决定这个界面忽略back键
            return true;
          }
          const handleBack = top.handleBack || top.component.handleBack;
          if (handleBack) {
            // 路由或组件上决定这个界面自行处理back键
            return handleBack();
          }
          // 默认行为: 退出当前界面。
          nav.pop();
          return true;
        }
        return false;
      };
    
    
    ##38、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=67&extra=page%3D1
    
    
    #39、手把手教React Native实战之复杂的组件通讯三种方案
    接着上节课的代码,从一个bug入手,透过问题去学习,大大提升学习效率
    解决bug:组件pop之后,之前的组件没有更新?
    例子:在购物车里清空了,但是pop之后,商品详情页并没有更新?
    3.更新阶段
    主要发生在用户操作之后或父组件有更新的时候,此时会根据用户的操作行为进行相应的页面结构的调整
    componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
    pop之后,数据已经改变了,但是之前的组件没什么变化,组件的数据不同步了,解决方案:
    方案1:监听didfocus事件,focus到当前路由的时候重新加载数据
                navigationContext.addListener('didfocus', callback)来替代
                componentWillMount() {
            console.log('List---componentWillMount');
            let navigator = this.props.navigator;
    
    
            let callback = (event) => {
                console.log(
                    'List : 事件类型',
                    {
                        route: JSON.stringify(event.data.route),
                        target: event.target,
                        type: event.type,
                    }
                );
            };
    
            // Observe focus change events from this component.
            this._listeners = [
                navigator.navigationContext.addListener('willfocus', callback),
                navigator.navigationContext.addListener('didfocus', callback),
            ];
        }
    
    
        componentWillUnmount(){
            console.log('List---componentWillUnmount');
            this._listeners && this._listeners.forEach(listener => listener.remove());
        }
        更新去取数据不用放到componentDidMount,直接放到didfocus的回调即可 不太稳定 
        
    方案2:参考第15讲视频Navigator参数传递:往下一个路由push的时候传递参数(一个回调),在组件pop之前先调用此回调刷新数据
    navigator.push({
                    name: 'GouWu',
                    component: GouWu,
                    params: {
    
                        fetchData: function () {
    
                            console.log('启动fetchData里的方法了');
    
                            AsyncStorage.clear(function (err) {
                                if (!err) {
                                    _that.setState({
                                        count: 0,
                                    });
    
                                    alert('购物车已经清空');
                                }
                            });
    
                        }
                    }
                })
                
                这是在点击清空购物车之后,马上pop,同时去触发回调
                clearStorage() {
            let _that = this;
    
            //触发一下回调 让数据同步
            console.log('点击了清空购物车');
            if (this.props.fetchData) {
                console.log('点击了清空购物车----回调去影响List页面');
                this.props.fetchData();
    
            }
    
            const { navigator } = this.props;
            if (navigator) {
    
                navigator.pop();
            }
    
    
        }
    
    还有一种情况:在点击清空购物车之后,不马上pop,而是通过点击物理back键去触发回调
    这个就要复杂很多,
    错误做法:
    const top = routers[routers.length - 1];
          console.log('栈顶的路由---'+top.component);
          if (top.component.props.fetchData) {
            console.log('回调fetchData了');
            top.component.props.fetchData();
          }
      注意:  route.component是一个class 而不是一个object instance ,在里面找props是不可能找得到的,
      如果一定需要从route上找到instance,需要在renderScene里给render的东西指定ref
    类似 <Component ref={r=>route.ref = r} />,然后通过route.ref来访问,但注意不应该假设route.ref总是有值
    一定要判断下 if(route.ref)
    
    
     
    
    方案3:采用redux/event等方式完成跨组件通讯
    
    社区主流还是redux,但是建议大家抛弃redux了,因为太繁琐了,我们马上有更方便的架构,来自nodejs社区的,不是前端的方案
    RN官方并不提供这个方案,redux也不是官方的
    涉及到十几个插件 核心是decorator   都是npm上的插件
    主要是一种 前端后端 结构和风格一致 的思想
    
    
    注意:方案1不推荐,推荐方案2或3
    
    
    ##39、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=76&extra=page%3D1
    
    
    
    #40、手把手教React Native实战之安装Nuclide与API学习AlertIOS
    
    安装mac下React Native的开发工具Nuclide
    
    FaceBook官方:nuclide 只支持Mac 基于Atom(github的)(Atom最大的特色就是可以安装很多的插件来完成我们的需求)炫酷插件
    
    https://atom.io/ 下载atom 
    
    https://nuclide.io/ 
    
    https://github.com/facebook/nuclide
    
    打开atom,如果nuclide安装成功,则可以看到nuclide的欢迎界面
    
    brew update && brew upgrade
    
    flow 一个静态的对js类型检查器
    
    brew install flow
    
    保存:mac (command+s)  windows(win+s)
    
    AlertIOS他的静态方法有两个:
    
    alert(title,message,[] buttons) 普通对话框
    
    prompt(title,message,[] buttons) 提供输入的对话框
    
    如果buttons为空数组,默认也会有一个ok按钮,如果数据的长度过长,按钮就会垂直排列!
    
    
    ##40、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=99&extra=page%3D1
    
    
    #41、手把手教React Native实战之API学习DatePickerAndroid与TimePickerAndroid
    
    日期、时间选择器  Android中是以api的形式,IOS是以组件的形式
    
    DatePickerAndroid:
    
    static open(options: Object) 
    
    打开一个标准的Android日期选择器的对话框
    
    可选的options对象的key值如下:
    
    date (Date对象或毫秒时间戳) - 默认显示的日期
    minDate (Date对象或毫秒时间戳) - 可选的最小日期
    maxDate (Date对象或毫秒时间戳) - 可选的最大日期
    在用户选好日期后返回一个Promise,回调参数为一个对象,其中包含有action, year, month (0-11), day。如果用户取消了对话框,Promise仍然会执行,返回的action为DatePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必先检查action的值。
    
    注意:当Android手机操作系统低于5.0时,设置最小和最大日期会导致api异常,最好不要设置,而是在用户选择完成后再进行检查;api中的Open函数打开的界面是系统的界面,不能设置其任何显示样式,如何手机显示不同是因为系统被厂商深度定制了
    
    TimePickerAndroid:
    
    static open(options: Object)
    
    打开一个标准的Android时间选择器的对话框。
    
    可选的options对象的key值如下:
    
    hour (0-23) - 要显示的小时,默认为当前时间。
    minute (0-59) - 要显示的分钟,默认为当前时间。
    is24Hour (boolean) - 如果设为true,则选择器会使用24小时制。如果设为false,则会额外显示AM/PM的选项。如果不设定,则采取当前地区的默认设置。
    在用户选好时间后返回一个Promise,回调参数为一个对象,其中包含有action, hour (0-23), minute (0-59)。如果用户取消了对话框,Promise仍然会执行,返回的action为TimePickerAndroid.dismissedAction,其他几项参数则为undefined。所以请在使用其他值之前务必先检查action的值。一般用TimePickerAndroid.timeSetAction的取反来判断
    
    注意:is24Hour在某些手机上不会产生作用,用户没有选择时间是因为按下了返回键或取消键;同样的api中的Open打开的是系统的界面
    
    
    ##41、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=107&extra=page%3D1
    
    
    
    #42、手把手教React Native实战之IOS日期时间组件DatePickerIOS
     
    nuclide代码自动补全提示的插件:
    atom-react-native-css atom-react-native-autocomplete
    
    nuclide自动保存代码的插件:
    autosave 需要setting enable
    
    
    日期时间选择器 在IOS中是以组件的形式 DatePickerIOS支持View组件的所有属性,可以设置他的宽度、高度、位置等
    
    这是一个受约束的(Controlled)组件,所以你必须监听onDateChange回调函数并且及时更新date属性来使得组件更新,否则用户的修改会立刻被撤销来确保当前显示值和props.date一致。
    
    除了View组件的属性,DatePickerIOS组件还支持如下属性:
    
    date 当前被选中的日期和时间 Date类型
    
    maximumDate minimumDate
    
    minuteInterval (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30)
    用来设置可选的最小分钟单位
    
    mode ('date', 'time', 'datetime') 选择器模式
    
    onDateChange 当用户修改日期或时间时调用此回调函数。
    唯一的参数是一个Date对象,表示新的日期和时间(也就是用户选择的)
    
    timeZoneOffsetInMinutes 以分钟为单位的时区时间差 默认情况下,选择器会选择设备的默认时区。通过此参数,可以指定一个时区。举个例子,要使用北京时间(东八区),可以传递8 * 60。
    
    注意:必须要把一个日期类型的状态机变量赋值给DatePickerIOS组件的date属性,并且在用户操作DatePickerIOS组件修改后,用onDateChange回调的新的date去更新对应的状态机变量,否则会出现用户使用DatePickerIOS组件修改改了时间,几秒钟后,DatePickerIOS组件又回到了原来的时间的情况。
    
    warning:Invalid prop 'date' of type 'Number'
    
    warning:Required prop 'onDateChange' was not specified
    
    警告的解决方案:
    
    这是一个bug,升级到0.28即可,如果不想升级,可以照这个修改:
    
    node_modules/react-native/Libraries/Components/DatePicker
    
    https://github.com/facebook/react-native/commit/cec913e7ce05d26181ab4d46e2e41d72acdfb87d
    
    http://stackoverflow.com/questions/35764088/prop-issues-with-datepickerios-in-react-native
    
    
    ##42、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=113&extra=page%3D1
    
    
    
    #43、手把手教React Native实战之API学习ActionSheetIOS
    
    需求:分享和弹出多项选择操作!在IOS开发中,ActionSheet提供了这样的功能,而React Native同样封装了该功能,那就是ActionSheetIOS
    
    提供了两个静态方法:
    
    static showActionSheetWithOptions(options,callback):
    
    在iOS设备上显示一个ActionSheet弹出框,其中options参数为一个对象,其属性必须包含以下一项或多项:
    
    options(字符串数组) - 一组按钮的标题(必选)
    
    cancelButtonIndex(整型) - 选项中取消按钮所在的位置(索引)
    
    destructiveButtonIndex(整型) - 红色高亮显示的位置(索引)
    
    title(字符串) - 弹出框顶部的标题
    
    message(字符串) - 弹出框顶部标题下方的信息
    
    static showShareActionSheetWithOptions(options,failureCallback,successCallback):
    
    在iOS设备上显示一个分享弹出框,其中options参数为一个对象,其属性必须包含以下一项或多项:
    
    message(字符串) - 要分享的信息
    
    url(字符串) - 要分享的URL地址
    
    注:如果url指向本地文件,或者是一个base64编码的url,则会直接读取并分享相应的文件。你可以用这样的方式来分享图片、视频以及PDF文件等。
    
    
    ##43、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=117&extra=page%3D1
    
    
    #44、手把手教React Native实战之API学习-网络状态与数据交互
    
    ##先来看看Android原生的:
    (安装最新版的AS)
    地址(翻墙):https://sites.google.com/a/android.com/tools/download/studio/canary/latest
    
    Latest Android Studio Canary Build: 2.2 Preview 4
    
    Windows(用迅雷下载): https://dl.google.com/dl/android/studio/ide-zips/2.2.0.3/android-studio-ide-145.3001415-windows.zip (436.8 MB)
    Mac: https://dl.google.com/dl/android/studio/ide-zips/2.2.0.3/android-studio-ide-145.3001415-mac.zip  (436.9 MB)
    Linux:  https://dl.google.com/dl/android/studio/ide-zips/2.2.0.3/android-studio-ide-145.3001415-linux.zip  (436.4 MB) 
    
    Android_SDK也得更新一下
    
    这里有一个坑:用最新版的as去打开之前的项目,报错:Error:Could not find com.android.tools.build:gradle-core:2.2.0-alpha2
    
    解决办法:复制旧版本的as中的2.2.0-alpha2到新版本as(有10几处地方),打开后会提示升级,升级到最新版本的alpha4
    
    启用gradle_daemon加速器:https://docs.gradle.org/2.9/userguide/gradle_daemon.html
    
    ##网络连接状态NetInfo:
    
    获取网络状态是异步的,使用了js的Promise机制
    
    Android平台的网络连接类型状态如下:
    
    1.NONE   设备没有网络连接
    
    2.BLUETOOTH  蓝牙数据连接
    
    3.DUMMY   虚拟数据连接
    
    4.ETHERNET  以太网数据连接
    
    5.MOBILE  手机移动网络数据连接
    
    6.MOBILE_DUN  拨号移动网络数据连接
    
    7.MOBILE_HIPRI  高权限的移动网络数据连接
    
    8.MOBILE_MMS   彩信移动网络数据连接
    
    9.MOBILE_SUPL   SUP网络数据连接
    
    10.VPN   虚拟网络连接 ,最低支持Android API 21版本
    
    11.WIFI   无线网络连接
    
    12.WIMAX   wimax网络连接
    
    13.UNKNOWN  未知网络数据连接
    
    根据文档说明:除此之外的其他一些网络连接状态已经被Android API隐藏了,但是我们可以在有需要的时候进行使用。
    
    IOS平台的网络连接类型状态如下:
    
    1.none   设备没有联网
    
    2.wifi     设备联网并且是连接的wifi网络,或者当前是iOS模拟器
    
    3.cell      设备联网是通过连接Edge,3G,WiMax或者LET网络
    
    4.unknown  该检测发生异常错误或者网络状态无从知道
    
    NetInfo有两个监听:
    
    1.网络状态改变的监听 回调当前网络的状态
    
    2.网络是否连接的监听 回调true或false
    
    Android独有的特色:
    
    1.NetInfo.isConnectionExpensive判断当前网络是否计费
    
    2.AndroidManifest.xml文件中添加如下权限字段:(需视频演示)
    
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    ##数据交互(网络请求与响应)
    
    抓包工具:httpwatch  下载地址:https://yunpan.cn/cRpfdwiYvu2jR  访问密码 f018
    
    IE中打开httpwatch的方法: shift+F2  Record Stop clear
    
    通过http或https协议与网络服务器交互,react native集成了node-fetch包以支持开发者的这种需求
    
    网络协议:http https
    
    网络请求方法:get post 等 默认是get
    
    1.GET使用URL或Cookie传参。而POST将数据放在BODY中。
    
    2.GET的URL会有长度上的限制,则POST的数据则可以非常大。
    
    3.POST比GET安全,因为数据在地址栏上不可见。
    
    百度一下:不再以讹传讹,GET和POST的真正区别
    
    建议:
    1.get方式的安全性较Post方式要差些,包含机密信息的话,建议用Post数据提交方式;
    
    2.在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式;
    
    准备需要传输的消息头:(标准消息头 自定义消息头)
    
    React Native使用http协议框架支持Accept-Encoding: gzip, deflate格式编码,开发者不需要对此进行设置
    
    自定义消息头可以在一些约定好的http消息头中填入身份认证信息
    
    RN中的网络访问api:Fetch(推荐) XMLHttpRequest
    
    fetch是一个更好的网络API,它由标准委员会提出,并已经在Chrome中实现。它在React Native中也默认可以使用。fetch的返回值是一个Promise对象,你可以用两种办法来使用它:1、使用then和catch指定回调函数 2、使用ES7的async/await语法来发起一个异步调用
    
      //如果你的服务器无法识别上面POST的数据格式,那么可以尝试传统的form格式
     map.body = 'username=13667377378&password=dfy889&act=signin';
    
        map.follow = 10;//设置请求允许的最大重定向次数,0为不允许重定向
    
        map.timeout = 8000;//设置超时时间,0为没有超时时间,这个值在重定向时会被重置
    
        map.size = 0;//设置请求回应中的消息体最大允许长度,0为没有限制
    
    XMLHttpRequest的实现几乎跟Web一样,唯一的区别就是(安全机制)rn中的XMLHttpRequest不存在跨域的限制,而是作为全局api实现的,你可以访问任何网站。但是,XMLHttpRequest基于iOS网络的
    
    let request=new XMLHttpRequest();
        request.onreadystatechange= (e)=>{
          if(request.readyState!==4){
            return ;
          }
          if(request.status===200){
            alert(request.resonsesText);
          }else{
            alert('出错啦');
          }
    
        };
        request.open('GET','http://www.reactnative.vip/');
        request.send();
    
    
    
    ##44、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=123&extra=page%3D1
    
    
    #45、手把手教React Native实战之API学习CameraRoll
    
    CameraRoll模块提供了对手机中保存的图片、视频文件进行遍历访问与操作。
    提供两个静态方法
    
    ##static getPhotos(params: object) 
    
    可以得到手机中所有的图片和视频(不仅仅是使用摄像头拍摄的照片、视频,还有各个应用自己下载到手机的图片与视频)
    
    params:对象 一些筛选的规则 有4个成员变量
    
    1.first 数值 希望获取多少张图片的信息
    
    2.groupTypes 字符串 默认为SavedPhotos [Album All Event Faces Library PhotoStream] 仅支持IOS平台 用来指定获取图片或视频的类型
    
    3.assetType 字符串 默认为Photos 表示只获取图片 [All Videos]
    
    4.after 字符串 用来记录上一次获取图片的结束标志 方便可以接着上次的位置继续获取 它的值不能由开发者随意赋予,而是应当在上一次获取图片后保存其值。通常,在Android平台,一开始就给这个值为null,但是在IOS平台,设置为null会抛一个无法捕捉的异常,导致红屏。
    
    返回一个带有图片标识符JSON对象的Promise
    
    Android平台的如下:
    
    ![微信号:dongfangyao888二维码](http://image18-c.poco.cn/mypoco/myphoto/20160630/11/1735166522016063011073201.png?512x638_130)
    
    IOS平台的如下:
    
    ![微信号:dongfangyao888二维码](http://image18-c.poco.cn/mypoco/myphoto/20160630/12/17351665220160630122358078.png?777x699_130)
    
    注意:不管是android平台还是ios平台,得到的image对象,可以作为一个整体,传递给Image组件,用来显示图片 
    
    可以分批次读取手机中的所有图片:监听ScrollView滑动到底部时,继续getPhotos,这时需要用after成员变量,递归调用getPhotos,当page_info.has_next_page为false时返回
    
    CameralRoll在IOS平台中需要添加链接库才能运行,否则报错找不到api:
    
    1.\node_modules\react-native\Libraries\CameraRoll下的Xcode项目文件RCTCameraRoll.xcodeproj拖动到当前Xcode项目的Libraries目录
    
    2.选中当前项目,在右边选择Build Phases,点击打开子项目Link Binary With Libraris
    
    3.打开第一步插入的RCTCameraRoll.xcodeproj,再打开它的子目录Products,将子目录下的libRCTCameraRoll.a文件拖到Link Binary With Libraris列表中
    
    4.使用Xcode重新运行项目
    
    
    ##static saveImageWithTag(tag) 保存一个图片到相册
    
     tag 在安卓上,本参数是一个本地URI(是把本地的图片保存到相册中),例如"file:///sdcard/img.png".
    
    在iOS设备上可能是以下之一:
    
    1、本地URI  2、资源库的标签  3、非以上两种类型,表示图片数据将会存储在内存中(并且在本进程持续的时候一直会占用内存)。
    
    返回一个Promise,操作成功时返回新的URI。
    
    
    
    ##45、配套视频(下载地址):http://www.reactnative.vip/forum.php?mod=viewthread&tid=156&extra=page%3D1
    
    
    #46、手把手教React Native实战之开源组件react-native-camera
    
    推荐一个跨平台的rn-camera-roll:https://www.npmjs.com/package/rn-camera-roll
    
    A Camera component for React Native. Also supports barcode scanning!二维码扫描
    
    原生Android Zxing google
    
    npm install rnpm -g
    
    rnpm link不是安装,而是添加原生依赖,对应的组件已经安装好了才能rnpm link
    
    通过这个例子来理解下react native的架构:js环境 jsBridge native环境
    
    业务逻辑是reactJs处理  ui用react写 但实际桥接成native
    
    ref的两种属性:String属性 回调属性(组件render渲染完成后的回调)
    
    官网:https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute
    
    this callback will be executed immediately after the component is mounted(组件render之后DidMount之前)
    
    
    ##46、配套视频(下载地址):http://www.reactnative.vip/thread-168-1-1.html
    
    
    #47、手把手教React Native实战之API学习定时器与手机定位Geolocation
    
    定时器API:setTimeout、setInterval、setImmediate、requestAnimationFrame 跟浏览器中的一致
    
    setTimeout:设置定时任务,隔多久去执行
    
    setInterval:设置循环执行的任务,每隔多久循环执行一次
    
    setImmediate:设置立即执行的任务
    
    requestAnimationFrame:用递归来设置动画;相对setTimeout(fn, 0)来说,有优势:能够在动画流刷新后执行,即上一个动画流会完整执行。
    
    requestAnimationFrame(fn)和setTimeout(fn, 0)不同,前者会在每帧刷新之后执行一次,而后者则会尽可能快的执行(在iPhone5S上有可能每秒1000次以上)。
    
    用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升。但是css3动画还是有不少局限性,比如不是所有属性都能参与动画、动画缓动效果太少、无法完全控制动画过程等等。所以有的时候我们还是不得不使用setTimeout或setInterval的方式来实现动画,可是setTimeout和setInterval有着严重的性能问题,虽然某些现代浏览器对这两函个数进行了一些优化,但还是无法跟css3的动画性能相提并论。这个时候,就该requestAnimationFrame出马了。requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API。
    
    setImmediate则会在当前JavaScript执行块结束的时候执行,就在将要发送批量响应数据到原生之前。注意如果你在setImmediate的回调函数中又执行了setImmediate,它会紧接着立刻执行,而不会在调用之前等待原生代码。Promise的实现就使用了setImmediate来执行异步调用。
    
    安装react-timer-mixin:npm i react-timer-mixin --save
    
    注意:Mixin属于ES5语法(js的混合封装方法),对于ES6代码来说,无法直接使用Mixin。如果你的项目是用ES6代码编写,同时又使用了计时器,那么你只需铭记在unmount组件时清除所有用到的定时器,那么也可以实现和TimerMixin同样的效果。我们发现很多React Native应用发生致命错误(闪退)是与计时器有关。具体来说,是在某个组件被卸载(unmount)之后,计时器却仍然被激活。
    
    
    使用moment.js轻松管理日期和时间:官网:http://momentjs.com/
    
    安装monent(时间格式化):npm i moment --save
    
    moment().format('YYYY-MM-DD HH:mm:ss'):取当前时间并格式化
    
    手机定位的api:Geolocation
    
    提供四个静态方法:getCurrentPosition watchPosition clearWacth stopObserving
    
    Android需要在清单文件(AndroidManifest.xml)中加权限:
    
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    
    IOS需要在Info.plist中增加NSLocationWhenInUseUsageDescription字段来启用定位功能。如果你使用react-native init创建项目,定位会被默认启用。
    
    综合案例:TimerDemo
    
    
    ##47、配套视频(下载地址):http://www.reactnative.vip/thread-182-1-1.html
    
    
    #48、手把手教React Native实战之API学习PanResponder手势识别
    
    这节课是PanResponder手势识别初探,高级部分放到vip专属课程里
    
    PanResponder平底锅的响应者
    
    PanResponder类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。
    
    RN框架底层的手势响应系统提供了响应处理器,PanResponder将这些手势响应处理器再次进行封装,以便开发者更容易对手势进行处理,更容易预测用户的手势,对每一个手势响应处理器,PanResponder除了为其提供代表触摸行为的原生事件外,还提供了一个新的手势状态对象用来详细描述手势的状态
    
    PanResponder的基本思想是:监视屏幕上指定大小、位置的矩形区域,当用手指按压这个区域中的某点后,开发者会收到这个事件,当按压后拖动手指时,会收到手势引发的各类事件,当手指离开这个矩形区域时,开发者也会收到相应的事件
    
    注意:开发者可以任意指定监视矩形区域的大小,但在这个区域里,只有第一个按下的事件会上报和继续监视处理,如果第一个手指按下还没有离开,接着第二个手指又来按下了,那么对第二个手指的各种触摸事件无法捕获
    
    注意:开发者可以在屏幕上指定多个监视矩形区域,但是不能同时监视多个矩形区域的不同触摸事件
    
    注意:监视区域会阻止被监视区域覆盖的组件接收触摸事件,比如监视区域覆盖了一个按钮,那么就无法通过按这个按钮来触发其对应的事件,只能在PanResponder监视器的事件处理中对触摸行为进行处理
    
    利用PanResponder实现监视器有以下几个步骤:
    
    1、指定监视区域
    
    如果监视区域有多个,一定不能重叠,否则都失效
    
    2、定义监视器相关变量
    
    指向监视器的变量(必须有)、指向监视器监视区域的变量(可以有)、记录监视区域左上角顶点坐标的两个数值变量(可以有)、上一次触摸点的横纵坐标变量(可以有)
    
    3、准备监视器的事件处理函数(有13个---高级课程会详叙)
    
    4、建立监视器(PanResponder.create)
    
    5、将监视器与监视区域关联 {...this.watcher.panHandlers}
    
    实例:点击、拖动选择百分百参数  比如说播放器的音量大小
    
    一个gestureState对象有如下的字段:
    
    stateID - 触摸状态的ID。在屏幕上有至少一个触摸点的情况下,这个ID会一直有效。
    
    moveX - 最近一次移动时的屏幕横坐标
    
    moveY - 最近一次移动时的屏幕纵坐标
    
    x0 - 当响应器产生时的屏幕坐标
    
    y0 - 当响应器产生时的屏幕坐标
    
    dx - 从触摸操作开始时的累计横向路程
    
    dy - 从触摸操作开始时的累计纵向路程
    
    vx - 当前的横向移动速度
    
    vy - 当前的纵向移动速度
    
    numberActiveTouches - 当前在屏幕上的有效触摸点的数量
    
    
    ##48、配套视频(下载地址):http://www.reactnative.vip/thread-191-1-1.html
    
    #49、手把手教React Native实战之运行官方项目UIExplorer(Android&IOS)
    
    马上就要进入vip专属课程了,我们用一个项目将之前讲的知识点串起来,适配Android与IOS!
    
    地址:https://github.com/facebook/react-native/tree/master/Examples/UIExplorer
    
    Android环境跑UIExplorer:
    
    1.下载ReactNative项目 80M左右
    
    git clone https://github.com/facebook/react-native.git
    
    2.进入react-native目录 编译android项目
    
    方式一:gradlew :Examples:UIExplorer:android:app:installDebug
    
    会去下载gradle可能报错:java.net.SocketTimeoutException: Read timed out javax.net.ssl.SSLHandshakeException: Remote host clos
    ed connection during handshake 这是网络问题引起 不用理 再一次运行gradlew命令 下载gradle比较慢 耐心等待即可
    
    ![gradlew](http://image18-c.poco.cn/mypoco/myphoto/20160710/15/17351665220160710151710035.png?670x168_130)
    
    方式二:gradle :Examples:UIExplorer:android:app:installDebug
    
    区别:Gradlew是包装器,自动下载包装里定义好的gradle 版本,保证编译环境统一,gradle 是用本地的gradle 如果是看过我的视频教程的就知道已经安装了gradle 在第11讲打包时
    
    报错:ndk找不到 ndk-build binary cannot be found, check if you've set $ANDROID_NDK environment variable correctly or if ndk.dir is setup in local.properties
    
    3.使用Android Studio安装配置ndk
    
    可以配置ANDROID_NDK环境变量或者在react-native目录下新建文件local.properties(里面设置了sdk与ndk路径)
    
    说到NDK开发,其实是为了有些时候为了项目需求需要调用底层的一些 C/C++ 的一些东西;另外就是为了效率更加高些;代码保护(apk的java层代码很容易被反编译,而C/C++库反汇难度较大)
    
    打开项目结构Project Structure:sdk jdk ndk(没有就会提示下载) ,as安装的话会安装到sdk目录下的ndk-bundle文件夹里
    
    下载地址(迅雷下载):https://dl.google.com/android/repository/android-ndk-r12b-windows-x86_64.zip
    
    下载地址(迅雷下载):https://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip
    
    
    Download https://downloads.sourceforge.net/project/boost/boost/1.57.0/boost_1_57_0.zip 放到目录\react-native\ReactAndroid\build\downloads
    
    boost_1_57_0下载地址:https://yunpan.cn/cBBT7LTwhg77i  访问密码 f1e7
    
    报错:Execution failed for task ':ReactAndroid:buildReactNdkLib'.
    > Process 'command 'F:\Android_SDK\ndk-bundle\android-ndk-r12b\ndk-build.cmd'' finished with non-zero exit value 2  解决方案:修改ndk的版本为r10e,不能使用最新版r12b
    
    4.BUILD SUCCESSFUL后开启packager服务器
    
    打开./packager/packager.sh 闪退的问题  解决方案:在react-native目录下npm install 在打开./packager/packager.sh 启动packager服务
    
    IOS环境跑UIExplorer:
    
    直接用Xcode打开UIExplorer.xcodeproj即可
    
    报错:packager抛出异常Error: Cannot find module 'chalk'
    
    解决:ls-l 在cd react-native目录下 npm install chalk
    
    npm install lodash  直接npm install 直到successful
    
    ##49、配套视频(下载地址):http://www.reactnative.vip/thread-203-1-1.html
    
    
    #50、手把手教React Native实战之混合原生开发_RN调用原生方法的步骤
    
    RN调用原生的方法,此讲适配Android原生与RN的混合开发,步骤如下:
    
    1.用AS打开一个已存在的项目,在RN项目中选择android/build.gradle文件
    
    2.在Android原生这边创建一个类继承ReactContextBaseJavaModule,这个类里面放我们需要被rn调用的方法,封装成了一个原生模块
    
    3.在Android原生这边创建一个类实现接口ReactPackage包管理器,并把第二步创建的类加到原生模块(NativeModule)列表里
    
    4.将第三步创建的包管理器添加到ReactPackage列表里(getPackages方法里)
    
    5.在RN中去调用原生模块 添加NativeModules从react-native
    
    
    报错: outDexFolder must be a folder 解决方法:不理它  或者 clean
    
    报错:> Failed to create \android\app\buildintermediates\debug\merging 解决方法:不理它  或者 clean
    
    报错:Could not delete path \android\app\build\generated\source\r\debug\com'.   解决方法:用AS build clean
    
    
    ##50、配套视频(下载地址):http://www.reactnative.vip/thread-210-1-1.html
    
    #63、手把手教React Native实战之API学习Linking跨app的通信方法_适配Android&IOS
    
    Linking提供了一个通用的接口来与传入和传出的App链接进行交互。
    
    方法:
    
    1.addEventListener(url,func) 添加一个监听Linking变化的事件
    
    2.removeEventListener(url,func) 删除一个事件监听
    
    3.openURL(url) 尝试使用设备上已经安装的应用打开指定的url 
    
      http网址:http://www.reactnative.vip
    
      https网址:https://www.baidu.com
    
      发短信:smsto:13667377378
    
    打电话:tel:13667377378
    
    发邮件:mailto:309623978@qq.com
    
    发位置:geo:37.484847,-122.148386 这个不一定看地图处理应用而定
    
    打开其他应用监听的意图url
    
    4.canOpenURL 判断设备上是否有已经安装的应用可以处理指定的URL 对于iOS 9以上版本,你还需要在Info.plist中添加LSApplicationQueriesSchemes字段
    
    5.getInitialURL() 如果应用是被一个链接调起的,则会返回相应的链接地址。否则它会返回null。
    
    注:如果要在Android上支持深度链接,请参阅http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
    
    意图过滤器需要单独列出:
    
     <intent-filter>
            	<action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <!-- Accepts URIs that begin with "http://www.example.com/gizmos” -->
            <data android:scheme="dfy"
                  android:host="reactnative.vip"
                  android:pathPrefix="/data" />
            	</intent-filter>
    
    能否通过adb启动activity:adb shell am start -n com.linkingdemo/.MainActivity
    
    测试是否能用url的形式打开app对应的activity:adb shell am start -W -a android.intent.action.VIEW -d "dfy://reactnative.vip/data" com.linkingdemo
    
    IOS
    
    首先我们需要在AppDelegate.m文件中引入RCTLinkingManager.h头文件,那么就需要我们引入相关配置了,关于库的引入默认项目都默认已经配置好的,但是我们需要配置一个库头文件搜索路径
    
    
    ##63、配套视频(下载地址):http://www.reactnative.vip/thread-327-1-1.html
    
    #未完待续。。。作者:东方耀 QQ:309623978
    
    
    

    转载于:https://my.oschina.net/u/3150996/blog/1574222

    展开全文
  • 之前在写纯前端的时候需要调用安卓的方法才能打电话,现在直接使用react native来进行写直接调用,太方便了 show(){ // let url = 'http://www.baidu.com'; Linking.openURL('tel:10086') } URL用来跳转链接界面...
  • react-native Linking.openURL('tel:'+phoneNum); andoid 第一种 /** * 拨打电话(直接拨打电话) * @param phoneNum 电话号码 */ public void callPhone(String phoneNum){ Intent intent = new Intent...
  • react native学习之Toast

    2016-01-19 23:59:28
    今天学习react native中的另外一些API,在android开发中,经常会需要用到ToastAndroid,其实facebook也封装好了该组件,ToastAndroid。ToastAndroid学习先看下使用ToastAndroid的方法和属性方法 static show(message:...
  • React Native 调用原生Android、iOS模块实现拨号功能一 前言由于前几个月公司2.0项目开发技术选型为React Native,技术部相关人员开始学习React Native相关的技术,笔者是一名Android开发者,下文所描述的React ...
  • Android开发平台 谷歌在2007年发布Android 是一个开源的基于 Linux 的移动设备操作系统 支持的设备: phone… 语言: 开发语言是java , 后来因为甲骨文准备对android java收费, 又开始向Kotlin转移 ...
  • React Native 中,NetInfo API 为我们提供了获取网络状态的方法。通过 NetInfo 我们可以检测到手机客户端设备当前的联网/断网状态。 属性&方法 isConnected:表示网路是否连接 fetch():获取网络状态 ...
  • ReactNative 中有 个模块NetInfo,可以获取设备的联网或者离线状态。 有如下几个方法: //获知设备联网或离线的状态信息 NetInfo.fetch().done((reach) => { // alert(reach); }); 这个reach为获取到的网络状态...
  • React Native网络状态解析及封装
  • React Native 内库中提供了NetInfo API获取设备当前的网络状态,直接使用即可。 componentWillMount() { NetInfo.fetch().done((status)=> { console.log('Status:'+status); }); } 获取网络...
  • React Native 调用原生Android、iOS模块实现拨号功能 一 前言 由于前几个月公司2.0项目开发技术选型为React Native,技术部相关人员开始学习React Native相关的技术,笔者是一名Android开发者,下文所描述的React ...
  • React Native 处理软件盘弹出和收回。 现在是有这样一个需求,就是,在TextInput中输入文本 ,会弹出软件盘 ,但是 ,当我点击空白处,软件盘却不退出,我想点击其他空白处,软件盘隐藏,怎么做了。软件盘之...
  • react native中用NetInfo判断网络状态
  • 一句话概要Native、Web App、Hybrid、React Native(后面以RN简称)、Weex 间的异同点,后期同步小程序和PWA。App常用开发模式简介此处...
1 2 3 4 5 ... 8
收藏数 144
精华内容 57
关键字:

native react 拨号