美文网首页React NativeReact NativeReact Native资料汇总
React Native 调用原生Android/iOS代码实现

React Native 调用原生Android/iOS代码实现

作者: 抱歉我孤独成性视你如命i | 来源:发表于2017-08-27 19:54 被阅读702次

    React Native 调用原生Android、iOS模块实现拨号功能

    一 前言

    由于前几个月公司2.0项目开发技术选型为React Native,技术部相关人员开始学习React Native相关的技术,笔者是一名Android开发者,下文所描述的React Native调用Android/iOS模块中关于iOS的部分如有误的地方,请指出。为了让从Android或iOS学习React Native的同志更加清楚的了解另一移动端,笔者尽可能写的详细点。

    二 效果

    下面两张图分别为iOS和Android上效果图,其中iOS效果图中点击电话号码会打印log,并不会调起iOS拨号界面,因为iOS模拟器不支持此功能,所以要想看效果只能用真机查看。这里打印log是为了证明React Native成功调起了原生iOS模块功能。

    react native调用iOS React Native调用Android

    三 实现方案

    关于调用拨号功能以及调用浏览器、短信、邮箱等功能,可有两种实现方案。

    一种是按照React Native提供的调用原生的过程方案来调用,这种适合大部分React Native调用原生功能的需求,掌握这种后,基本以后再有调用原生需求即可按照此过程方案解决,此文也会选用这种方案进行描述。

    另一种是React Native帮我们封装的Linking模块可以实现这类的需求,这种相比上一种来说相对简单,主要适用于调用原生的电话、短信、邮箱、浏览器等功能。

    四 实现原生Android模块

    1.在自己新建的Reacat Native项目中android/app/src/main/java/xxx(项目包名)/ 目录下(为了和其他文件分离,笔者又在此目录下新建一个native文件夹),需要新建一个java类文件,例如文件名为CallPhoneModule.java,这个java类一定要继承RN提供的ReactContextBaseJavaModule抽象类,然后实现其构造函数,其中的参数要为ReactApplicationContext reactContext。

    public class CallPhoneModule extends ReactContextBaseJavaModule {
        public CallPhoneModule(ReactApplicationContext reactContext) {
            super(reactContext);
        }
     }
    
    CallPhoneModule

    2.然后实现NativeModule中定义的getName()方法,返回一个String类型字符串,这个返回结果将要在JavaScript中使用,例如返回“CallPhoneModule”,则可以在JavaScript中通过React.NativeModules.CallPhoneModule调用。注意,如果返回的字符串中有RCT前缀,则会自动移除RCT前缀。例如返回“RCTCallPhoneModule”,则在JavaScript中依然可以通过React.NativeModules.CallPhoneModule调用。CallPhoneModule继承ReactContextBaseJavaModule,ReactContextBaseJavaModule继承BaseJavaModule,BaseJavaModule实现了NativeModule接口,这是CallPhoneModule与NativeModule的关系。

     @Override
        public String getName() {
            return "CallPhoneModule";
        }
    

    3.然后在CallPhoneModule类中写一个方法,这个方法提供给JavaScript调用,例如方法名为callPhone,里面传递String类型参数(非必须),特别的这个方法要使用@ReactMethod注解,以及返回类型必须为void。然后在callPhone方法中写入要实现的功能,这里写入了拨号功能的实现。

     Intent intent = new Intent(Intent.ACTION_DIAL,  Uri.parse("tel:" + phoneString));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            this.reactContext.startActivity(intent);
    

    CallPhoneModule.java文件的全部代码如下:

    package com.zhuku02;
    
    import android.content.Intent;
    import android.net.Uri;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.bridge.ReactContextBaseJavaModule;
    import com.facebook.react.bridge.ReactMethod;
    import java.lang.String;
    
    public class CallPhoneModule extends ReactContextBaseJavaModule {
    
        public ReactApplicationContext reactContext;
    
        public CallPhoneModule(ReactApplicationContext reactContext) {
            super(reactContext);
            this.reactContext = reactContext;
        }
    
        @ReactMethod
        public void callPhone(String phoneString) {
            Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneString));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            this.reactContext.startActivity(intent);
        }
    
        @Override
        public String getName() {
            return "CallPhoneModule";
        }
    }
    
    CallPhoneModule

    4.新建一个java类文件,例如文件名为CallPhoneReactPackage.java,这个类必须实现ReactPackage接口,然后实现createViewManagers、createNativeModules两个方法,特别的要在createNativeModules方法的返回值中add进刚才新建的CallPhoneModule类。

    CallPhoneReactPackage.java全部代码如下:

    package com.zhuku02;
    
    import com.facebook.react.ReactPackage;
    import com.facebook.react.bridge.NativeModule;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.uimanager.ViewManager;
    import com.zhuku02.CallPhoneModule;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class CallPhoneReactPackage implements ReactPackage {
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    
        @Override
        public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
            List<NativeModule> modules = new ArrayList<>();
    
            modules.add(new CallPhoneModule(reactContext));
    
            return modules;
        }
    }
    
    CallPhoneReactPackage

    5.最后在MainApplication.java文件中的getPackages方法中加上刚才新建的CallPhoneReactPackage类。至此,原生Android模块书写完毕。关于JavaScript调用原生Android模块代码会在文末和调用原生iOS一起写出。

    修改后的MainApplication.java文件代码如下:

    package com.zhuku02;
    
    import android.app.Application;
    import com.facebook.react.ReactApplication;
    import com.facebook.react.ReactNativeHost;
    import com.facebook.react.ReactPackage;
    import com.facebook.react.shell.MainReactPackage;
    import com.facebook.soloader.SoLoader;
    
    import com.zhuku02.CallPhoneReactPackage;
    
    import java.util.Arrays;
    import java.util.List;
    
    
    public class MainApplication extends Application implements ReactApplication {
    
        private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
            @Override
            public boolean getUseDeveloperSupport() {
                return BuildConfig.DEBUG;
            }
    
            @Override
            protected List<ReactPackage> getPackages() {
                return Arrays.<ReactPackage>asList(
                        new MainReactPackage(),
                        new CallPhoneReactPackage()
                );
            }
        };
    
        @Override
        public ReactNativeHost getReactNativeHost() {
            return mReactNativeHost;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            SoLoader.init(this, /* native exopackage */ false);
        }
    }
    
    
    MainApplication

    五 实现原生iOS模块

    1.在自己新建的Reacat Native项目中ios/xxx(项目包名)/ 目录下,需要新建一个后缀为m和一个后缀为h的文件。为了和其他文件分离以及和Android保持一致,笔者又在此目录下新建一个native文件夹。在Xcode的此文件夹上右键New File,然后在弹出的页面中Cocoa Touch Class选项输入文件名,这样会建立出相同文件名的m和h文件。如果New File时,分别选择Objective-C File和Header File,则这两个文件名要相同。例如文件名称为CallPhoneModuleIos。

    2.在CallPhoneModuleIos.h文件中,类要实现RN提供的RCTBridgeModule协议。RCT是ReaCT的缩写,React Native中Object-C相关的命名均以RCT开头。RCTBridgeModule是定义好的protocol,实现该协议的类,会自动注册到Object-C对应的Bridge中。Object-C Bridge上层负责与Object-C通信,下层负责和JavaScript Bridge通信,而JavaScript Bridge负责和JavaScript通信。这样,通过Object-C Bridge和JavaScript Bridge就可以实现JavaScript和Object-C的相互调用。

    CallPhoneModuleIos.h文件如下:

    
    #import <UIKit/UIKit.h>
    #import <React/RCTBridgeModule.h>
    #import <React/RCTLog.h>
    
    @interface CallPhoneModuleIos : NSObject <RCTBridgeModule>
    
    @end
    
    
    CallPhoneModuleIos

    3.CallPhoneModuleIos.m文件中,类需要包含RCT_EXPORT_MODULE()宏,作用是自动注册一个module。这个宏可以添加一个参数,用来指定在JavaScript调用这个模块的名字,类似于上文中说的getName()方法。如果不添加这个参数,则默认就是这个类的名字。

    4.然后需要在此类中写一个方法,提供给RN调用,方法通过RCT_EXPORT_METHOD()宏来实现。

    RCT_EXPORT_METHOD(callPhone: (NSString *)phone){
       NSLog(@"======%@",phone);
    }
    

    CallPhoneModuleIos.m完整代码:

    #import "CallPhoneModuleIos.h"
    #import <Foundation/Foundation.h>
    
    @implementation CallPhoneModuleIos
    
    RCT_EXPORT_MODULE(CallPhoneModuleIos);
    
    RCT_EXPORT_METHOD(callPhone: (NSString *)phone){
      
       NSLog(@"======%@",phone);
      //去掉注释,下面代码就是实现拨号功能代码,但还未真机测试
    //  NSMutableString * str = [[NSMutableString alloc] initWithFormat:@"telprompt://%@",phone];
    //  [[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
      
    }
    
    // -(dispath_queue_t)methodQueue{
    //     return dispath_get_main_queue();
    // }
    
    @end
    
    
    CallPhoneModuleIos

    至此,则原生iOS代码书写完成,现在即将开始调用。

    六 React Native调用Android、iOS原生模块

    为了在JavaScript端同时访问Android、iOS原生模块更加方便,笔者把原生模块的调用封装在一个JavaScript文件中,例如文件名为CallPhone.js,这样在需要调用的地方直接调用此JavaScript文件既可,同时在此文件中,处理好Android、iOS、Web(若有)的分别调用。

    import {Platform, NativeModules} from 'react-native';
    
    var module = null;
    if (Platform.OS == 'ios') {
        module = NativeModules.CallPhoneModuleIos;
    } else if (Platform.OS == 'android') {  
        module = NativeModules.CallPhoneModule;
    } else if (Platform.OS == 'web') {
        //暂未实现web功能  
    }
    export default module;
    
    CallPhone

    然后在JavaScript文件中这样调用:

    import CallPhone from '../../native/CallPhone';
      CallPhone.callPhone('4007773177');
    

    到这里,整篇文章就结束了,疑问、建议或者指教欢迎讨论。

    七 参考资料

    native-modules-ios
    native-modules-android

    原创文章,转载请注明出处。

    相关文章

      网友评论

      本文标题:React Native 调用原生Android/iOS代码实现

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