Android开发分享RNReact Native

通过高德地图学习RN与Android原生的混合开发

2016-11-03  本文已影响1544人  JustCode

在原生的开发中使用高德或者百度地图实现定位等相关功能是每一个小伙伴必备的技能,那么现在我要在RN中实现定位的功能该怎么做呢?一看到需要实现这样的功能,第一反应就是打开高德开放平台看看是否有相关的SDK,可是翻来翻去也只看到了Android原生的实现方式。但是,RN可以实现与原生的混合开发,那么是不是可以尝试下在RN页面调用原生里面的定位功能呢?

尝试开始(内心还是有点小激动...):

1.在Android工程中完成相关配置

此步骤跟原生开发没有任何的区别,可以参照高德开放平台,此处不再介绍。

<meta-data 
     android:name="com.amap.api.v2.apikey"                          
     android:value="you key" />

2.创建原生模块

原生模块是一个继承于ReactContextBaseJavaModule的Java类

创建一个继承ReactContextBaseJavaModule的Java类,并在此类中实现定位功能,先上代码:


public class AMapLocationModule extends ReactContextBaseJavaModule {    
      private ReactApplicationContext mReactApplicationContext;       
      private AMapLocationClient mLocationClient = null;    
      // 定位回调监听器   
      private AMapLocationListener mAMapLocationListener = new AMapLocationListener() {     
          @Override     
          public void onLocationChanged(AMapLocation aMapLocation) { 
               // 实例化一个回调给RN端的map对象
               WritableMap params = Arguments.createMap();           
               if (aMapLocation != null) {               
                   if (aMapLocation.getErrorCode() == 0) {                    
                        // 定位成功                                  
                        params.putString("address", aMapLocation.getAddress());               
                    } else {                    
                        // 定位失败                                      
                        params.putBoolean("result", false);                
                    }          
               }           
               // 发送给RN端  
               sendEvent("onLocationChanged", params);       
            }    
       };    
       private void sendEvent(String eventName, @Nullable WritableMap params) {        
              if (mReactApplicationContext != null) {         
                    mReactApplicationContext                       
                            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)                   
                            .emit(eventName, params);        
              }    
        }    
        public AMapLocationModule(ReactApplicationContext reactContext) {        
               super(reactContext);        
               // 在构造函数中实例化定位功能的相关对象,并设置相关的定位配置,跟原生实现定位功能一样配置
               mReactApplicationContext = reactContext;        
               mLocationClient = new AMapLocationClient(reactContext);    
               mLocationClient.setLocationListener(mAMapLocationListener);    
               AMapLocationClientOption clientOption = new AMapLocationClientOption();        
               clientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving); // 低功耗模式, 只使用wifi        
               clientOption.setOnceLocation(true);        
               mLocationClient.setLocationOption(clientOption);    
        }   
        @Override    
        public String getName() {       
             return "AMapLocation";   //此Name在RN端标记这个模块,不能与已有的Name发生冲突
        }    
        @ReactMethod    //  可以被RN端调用的方法
        public void destory() {       
               if (mLocationClient != null) {          
                    mLocationClient.stopLocation(); // 停止定位   
                    mLocationClient.onDestroy(); // 销毁定位      
               }    
         }    
         @ReactMethod   // 可以被RN端掉用的方法,开启定位
         public void startLocation() {   
               if (mLocationClient != null) {   
                   mLocationClient.startLocation();       
               }   
         }
}

在上述的代码中,必须注意以下几个点:

3. 注册模块

在第二个步骤中,我们将可以被RN调用的原生模块给创建好了,为了让RN端可以识别此模块,就少不了注册这一个步骤。
注册模块相对简单一点,创建一个实现ReactPackage接口的Java类,实现相应的方法就OK了,下面看下代码:

public class AMapLocationReactPackage implements ReactPackage {    
      @Override    
      public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { 
             List<NativeModule> list = new ArrayList<>();       
             list.add(new AMapLocationModule(reactContext));        
             return list;   
      }    
      @Override   
      public List<Class<? extends JavaScriptModule>> createJSModules() {       
             return Collections.emptyList();   
      }   
      @Override    
      public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {  
             return Collections.emptyList();  
      }
}

最后需要记住在Application里面ReactNativeHostgetPackages()方法里面添加上AMapLocationReactPackage实例。

AMapLocationReactPackage这个类中,需要实现三个方法:

到这Android原生端的代码就告一段落了,来个中场休息吧(啦啦队该上场...),接下来实现下RN端的代码就能够知道我这个尝试是否能够成功了。

4.在RN端获取模块

还记得在创建模块的时候讲过,getName()方法返回了一个字符串,那么在RN端通过此字符串就能获得相对应的模块的引用了。所以此例子中,在RN端通过NativeModules.AMapLocation就能获取刚刚创建的模块实例,这意味着现在已经可以调用模块中通过ReactMethod注解的方法了,为了更好的使用,我做了个简单的封装。

import {NativeModules, DeviceEventEmitter} from 'react-native';
const location = NativeModules.AMapLocation;
export default class AMapLocation {    
       // 开启定位
       static startLocation() {        
            location.startLocation();    
       }    
       // 关闭定位  
       static destory() {        
            location.destory();    
       }
       // 注册定位回调监听   
       static addEventListener(handler) {        
            const listener = DeviceEventEmitter.addListener(      
                            'onLocationChanged',   // 与模块中的eventName保持一致  
                             handler       // 回调函数,在此函数接收定位信息
                             );        
            return listener;    
       }
}

5.在RN端开启定位服务并接收定位数据

接下来就在RN端开启个定位服务,看看能不能成功开启并且接受到当前的地址信息。


import AMapLocation from '../modules/AMapLocation';

componentDidMount() {    
      this.listener = AMapLocation.addEventListener(this._onLocationChanged);    // 注册监听
      AMapLocation.startLocation(); // 开启定位
}
componentWillUnmount() {    
      AMapLocation.destory();    
      this.listener.clear();
}
_onLocationChanged = (data)=> {   
     if (data && data.result) {        
           console.log(data.address);        
     }
};

很常规的做法,在componentDidMount ()方法中注册监听并开启定位;在componentWillUnmount()方法中关闭定位,清除监听事件;
_onLocationChanged()方法中接收数据。

6.验证结果(鸡冻ing...)

历经千辛万苦终于到了这一步了,那么就来看下log吧。

log.png

地址信息从logo中显示出来了,也就意味着这次尝试成功了!

6.总结

通过此次尝试差不多也就学会了RN与原生的一种混合开发方式,那就来让我们回忆一下混合开发大致的步骤吧。

通过原生向RN发送事件的方法实现了高德地图的定位功能,这是一次成功的尝试,但这才迈出了第一步。。。

上一篇 下一篇

猜你喜欢

热点阅读