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 调用原生Android/iOS代码实现拨号功能_第1张图片

React Native 调用原生Android/iOS代码实现拨号功能_第2张图片

三 实现方案

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

一种是按照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);    } }

React Native 调用原生Android/iOS代码实现拨号功能_第3张图片

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";    }}

React Native 调用原生Android/iOS代码实现拨号功能_第4张图片

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 createViewManagers(ReactApplicationContext reactContext) {        return Collections.emptyList();    }    @Override    public List createNativeModules(ReactApplicationContext reactContext) {        List modules = new ArrayList<>();        modules.add(new CallPhoneModule(reactContext));        return modules;    }}

React Native 调用原生Android/iOS代码实现拨号功能_第5张图片

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 getPackages() {            return Arrays.asList(                    new MainReactPackage(),                    new CallPhoneReactPackage()            );        }    };    @Override    public ReactNativeHost getReactNativeHost() {        return mReactNativeHost;    }    @Override    public void onCreate() {        super.onCreate();        SoLoader.init(this, /* native exopackage */ false);    }}

React Native 调用原生Android/iOS代码实现拨号功能_第6张图片

五 实现原生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 #import #import @interface CallPhoneModuleIos : NSObject <RCTBridgeModule>@end

React Native 调用原生Android/iOS代码实现拨号功能_第7张图片

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 @implementation CallPhoneModuleIosRCT_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

React Native 调用原生Android/iOS代码实现拨号功能_第8张图片

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

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

为了在JavaScript端同时访问Android、iOS原生模块更加方便,笔者把原生模块的调用封装在一个JavaScript文件中,这样在需要调用的地方直接调用此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;

React Native 调用原生Android/iOS代码实现拨号功能_第9张图片

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

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

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

七 参考资料

native-modules-ios
native-modules-android

原创文章,来自于Vitamio,转载请注明出处。

更多相关文章

  1. Android:apk文件结构
  2. Android Layout文件的属性说明
  3. android “分享”功能的实现
  4. Android 中各种JAVA 包的功能描述
  5. 在Android中建立Android project没有R.java文件
  6. [入门二]Android中各种JAVA包的功能描述
  7. Android的相关文件类型

随机推荐

  1. Android之利用TextWatcher制作自定义编辑
  2. Android 云端推送C2DM php实现向终端推送
  3. Android之创建文件、目录
  4. Android仿QQ的设置与帮助使用PreferenceA
  5. Android 软键盘相关
  6. Android2.2 新特性
  7. Android:Activity中onCreate方法的参数及
  8. Android调用系统相机拍照并保存,解决OOM
  9. Android 混淆代码的时候出现问题
  10. Android 切换全屏,取消全屏