美文网首页
前端知识 | React-Native如何自己撸第三方库之and

前端知识 | React-Native如何自己撸第三方库之and

作者: SEATELL海说软件 | 来源:发表于2018-02-08 10:39 被阅读0次

    在使用 ReactNative 开发过程中,由于开发中用到的语言是 JS,而如果需要实现百度定位或者微博分享等第三方 SDK 时,往往会先去找有没有支持 React Native 的三方库。

    尽管大部分常用功能已经被民间艺人或官方团队实现,但是一旦遇到未被 RN 开发的就只能撸起袖子自己干了。ReactNative 官方文档也介绍了 Native Modules(下称‘原生模块’)的使用方法,它能用于访问原生平台的 API。

    本文主要提供 Android 平台的原生模块打包教程。

    原生模块的使用方法:

    以官网文档列举的 Toast 模块使用方法为例,其主要步骤为:

    第一步:

    使用 Android Studio 打开 RN 项目的 android 文件,新建 Android Library 命名为 react-native-toast

    图1 新建Android Library

    第二步:

    在 react-native-toast 的build.gradlew 中添加RN依赖

    dependencies {

    ....

    compile

    "com.facebook.react:react-native:+"         //here

    }

    在 app 的 build.gradlew 中引入这个库

    dependencies {

    ....

    compile project(

    ':react-native-toast')//here

    }

    第三步:

    前面的环境都配置好后就开始新建2个 java 文件:

    继承 ReactContextBaseJavaModule 的 java 类Module.java 

    和注册模块用的Package.java。

    具体代码在官网有详细提供,本文不重点阐述

    思考:

    如果按照 RN 文档方法,在项目的 android 根文件夹下添加原生模块,会出现两个问题:一是,如果要实现的原生模块多了,Android Library 也会递增,目录容易混乱难以管理;二是,这样的原生模块不容易复用,其它项目没法直接使用这个原生模块。

    通行的做法是,将实现后原生模块打包好,然后存放在项目的 node_modules 的文件内,供 APP 调用。

    本文重点:

    本文将以百度定位的 Android SDK 为例,介绍如何将其打包为一个名为 “react-native-baidu-location” 的原生模块库(library),供 RN APP 调用。

    这个例子相比一般的原生模块开发(RN文档示例)会多一项工作,即引入 SDK,流程大致如下:

    ·创建一个 RN 项目 Demo,用于调试。

    ·初始化 react-native-baidu-location 包。

    ·根据官网文档对 Android 平台配置、引入 SDK、写代码。

     初始化原生模块库

    先创建一个 RN 项目 Demo

    安装 react-native-create-library(类似的工具还有react-native-create-bridge)

     npm install -g  react-native-create-library

    在 node_modules 文件夹下创建你的三方库

     react-native-create-library  react-native-baidu-location

    之后进行本文之前的第三步,第一步和第二步已经帮我们实现,只需要根据自己需求修改构建工具的版本  .grandle 和 buildToolsVersion。

    打包 Android 部分(重难点)

    因为以百度定位为例,所以需要申请为百度开发者,下载基础定位 SDK,具体步骤请使用 baidu,本文不必阐述,主要使用下载后解压包内叫 libs 的文件夹。

    使用 Android Studio 打开 react-native-baidu-location 内的 android 文件和 RN 项目Demo 下的 android 文件,因为这里是 android 打包教程,所以其他平台教程请期待下篇《React-Native 如何自己撸第三方库之 ios 篇》

     1.React-native-baidu-location - android

    将 libs 文件复制到 android 文件下

     build.gradle 加入如下代码

    android  {

         ....

       sourceSets {

            main {

                jniLibs.srcDirs = ['libs']

            }

        }

    }

    2.Demo - android

    根据百度文档,配置相关服务,ak 秘钥和权限

    AndroidManifest.xml 加入如下代码

                 android:name="com.baidu.location.f"

                android:enabled="true"

                 android:process=":remote">

                 android:name="com.baidu.lbsapi.API_KEY"

                 android:value="GN1lCG*************4I&&s" />

    添加权限

    ```

    ```

    3. 编写 Native 模块

    和前文的第三步一样使用固定写法:

    1.     建一个中间访问对象,

    2.     建一个 ReactPackage 对象.

    3.     将 ReactPackage 对象加载到 MainApplication 中.

    LocationActivity

    package  com.location;

    import  android.util.Log;

    import  com.baidu.location.BDLocation;

    import  com.baidu.location.BDLocationListener;

    import  com.baidu.location.LocationClient;

    import  com.baidu.location.LocationClientOption;

    import  com.baidu.location.Poi;

    import  com.facebook.react.bridge.Callback;

    import  com.facebook.react.bridge.ReactApplicationContext;

    import  com.facebook.react.bridge.ReactContextBaseJavaModule;

    import  com.facebook.react.bridge.ReactMethod;

    import  java.util.List;

    /**

     * Created by luokun on 2018/1/31.

     */

    public  class LocationActivity extends ReactContextBaseJavaModule {

        public LocationClient mLocationClient =  null;

        private Callback locationCallback;

        public  LocationActivity(ReactApplicationContext reactContext) {

            super(reactContext);

        }

        @ReactMethod

        public void startLocation( Callback  locationCallback) {

            this.locationCallback =  locationCallback;

            mLocationClient = new  LocationClient(getReactApplicationContext());     //声明LocationClient类

             mLocationClient.registerLocationListener(myListener);    //注册监听函数

            LocationClientOption option = new  LocationClientOption();

            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy

            );//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备

             option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系

            int span = 0;

            option.setScanSpan(span);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的

            option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要

            option.setOpenGps(true);//可选,默认false,设置是否使用gps

            option.setLocationNotify(true);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果

             option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”

             option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到

            option.setIgnoreKillProcess(false);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死

             option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集

            option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤gps仿真结果,默认需要

            mLocationClient.setLocOption(option);

            mLocationClient.start();

             Log.e("tag","ok");

        }

        /**

         * 定位回掉

         */

        public BDLocationListener myListener =  new BDLocationListener() {

            @Override

            public void onReceiveLocation(final  BDLocation bdLocation) {

                Log.e("TGA", "回掉+1");

                //Receive Location

                final StringBuffer sb = new  StringBuffer(256);

                sb.append("time : ");

                sb.append(bdLocation.getTime());

                sb.append("\nerror code :  ");

                sb.append(bdLocation.getLocType());

                sb.append("\nlatitude :  ");

                 sb.append(bdLocation.getLatitude());

                sb.append("\nlontitude :  ");

                 sb.append(bdLocation.getLongitude());

                sb.append("\nradius :  ");

                sb.append(bdLocation.getRadius());

                if (bdLocation.getLocType() ==  BDLocation.TypeGpsLocation) {// GPS定位结果

                    sb.append("\nspeed :  ");

                     sb.append(bdLocation.getSpeed());// 单位:公里每小时

                    sb.append("\nsatellite :  ");

                     sb.append(bdLocation.getSatelliteNumber());

                    sb.append("\nheight :  ");

                     sb.append(bdLocation.getAltitude());// 单位:米

                    sb.append("\ndirection :  ");

                     sb.append(bdLocation.getDirection());// 单位度

                    sb.append("\naddr :  ");

                     sb.append(bdLocation.getAddrStr());

                    sb.append("\ndescribe :  ");

                    sb.append("gps定位成功");

                } else if  (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {// 网络定位结果

                    sb.append("\naddr :  ");

                     sb.append(bdLocation.getAddrStr());

                    //运营商信息

                     sb.append("\noperationers : ");

                    sb.append(bdLocation.getOperators());

                    sb.append("\ndescribe :  ");

                    sb.append("网络定位成功");

                } else if  (bdLocation.getLocType() == BDLocation.TypeOffLineLocation) {// 离线定位结果

                    sb.append("\ndescribe :  ");

                    sb.append("离线定位成功,离线定位结果也是有效的");

                } else if  (bdLocation.getLocType() == BDLocation.TypeServerError) {

                    sb.append("\ndescribe :  ");

                    sb.append("服务端网络定位失败,可以反馈IMEI号和大体定位时间到loc-bugs@baidu.com,会有人追查原因");

                } else if (bdLocation.getLocType()  == BDLocation.TypeNetWorkException) {

                    sb.append("\ndescribe :  ");

                    sb.append("网络不同导致定位失败,请检查网络是否通畅");

                } else if  (bdLocation.getLocType() == BDLocation.TypeCriteriaException) {

                    sb.append("\ndescribe :  ");

                    sb.append("无法获取有效定位依据导致定位失败,一般是由于手机的原因,处于飞行模式下一般会造成这种结果,可以试着重启手机");

                }

                 sb.append("\nlocationdescribe : ");

                 sb.append(bdLocation.getLocationDescribe());// 位置语义化信息

                List list =  bdLocation.getPoiList();// POI数据

                if (list != null) {

                    sb.append("\npoilist  size = : ");

                    sb.append(list.size());

                    for (Poi p : list) {

                        sb.append("\npoi= :  ");

                        sb.append(p.getId() +  " " + p.getName() + " " + p.getRank());

                    }

                }

                 locationCallback.invoke(sb.toString());

            }

        };

        @Override

        public String getName() {

            return "Location";

        }

    }

    LocationPackage

    package  com.location;

    import  com.facebook.react.ReactPackage;

    import  com.facebook.react.bridge.JavaScriptModule;

    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;

    /**

     * Created by luokun on 2018/1/31.

     */

    public  class LocationPackage implements ReactPackage {

        @Override

        public List  createViewManagers(ReactApplicationContext reactContext) {

            return Collections.emptyList();

        }

        @Override

        public List  createNativeModules(

                ReactApplicationContext  reactContext) {

            List modules =  new ArrayList<>();

            modules.add(new  LocationActivity(reactContext));    //

            return modules;

        }

    }

    Index.js文件

    'use  strict';

    import  { NativeModules } from 'react-native';

    export  default NativeModules.Location;

    恭喜完成!

    至于怎么使用,最好写一个 README.md,要‘装逼’咱们就来全套。写个使用文档,让我们搬运工们用得顺手。(笑笑就好:))

    使用方法:

    自动 link

    React-native-baidu-location  link

    或者手动 link

    /android/settings.gradle

    include  ':react-native-baidu-location'

    project(':react-native-baidu-location').projectDir  = new File(rootProject.projectDir,  '../node_modules/react-native-baidu-ocr/android')

    /android/app/build.gradle

    dependencies  {

       ...

        compile  project(':react-native-baidu-ocr'') // 加入

       ...

    }

    js 使用方法

    Import  Location from ‘react-native-baidu-location’

    ...

    ...

     componentDidMount() {

             Location.startLocation((location)=> {

                console.log(location)       

    });

        }

    当你看到这里的时候并且自己照着写了一遍,那么恭喜你成功开发出第三方 rn 库了,甚至可以上传到 npm 上开源。

    上传成功后,其它项目就可以通过 npminstall 来使用这个库。

    总结:

    要打包 React Native 的原生模块,你最好有以下知识储备:

    有 RN 开发经验。如 RN 文档所说,原生模块是该框架的高级特性,当然是有一定的经验更易理解。

    了解 Java 和 Objective-C, 至少能看懂这两种代码。和官网教程对比上述代码虽然多但是很多都是固定写法。

    基本实现原理是通过回调使 JavaScript 能够访问到 java 返回值。

    更多特性敬请期待。

    -END- 

    相关文章

      网友评论

          本文标题:前端知识 | React-Native如何自己撸第三方库之and

          本文链接:https://www.haomeiwen.com/subject/vgozzxtx.html