博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React Native 调用原生Android、iOS模块实现拨号功能
阅读量:6222 次
发布时间:2019-06-21

本文共 7293 字,大约阅读时间需要 24 分钟。

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提供的调用原生的过程方案来调用,这种适合大部分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);    } }复制代码

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";    }}复制代码

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; }}复制代码

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); }}复制代码

五 实现原生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
@end复制代码

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复制代码

至此,则原生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;复制代码

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

import CallPhone from '../../native/CallPhone';  CallPhone.callPhone('4007773177');复制代码

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

七 参考资料

转载于:https://juejin.im/post/5a30a498f265da4310485dc7

你可能感兴趣的文章
二叉树
查看>>
赋予用户库的读写权限
查看>>
PHP取得用户真实IP
查看>>
XML文档语法 学习笔记
查看>>
组织级安全编码实践
查看>>
国内外SNS比较分析
查看>>
谈PCIe ssd在数据库优化中的作用
查看>>
《Android移动网站开发详解》
查看>>
JTListView
查看>>
android getResources的作用
查看>>
指示器随机变量
查看>>
ubuntu14.04安装Scrapy爬虫
查看>>
Ubuntu 16.04 source.list content
查看>>
为什么servlet中无法直接autowired bean from applicationC...
查看>>
windows 下 django 卸载与重装
查看>>
sublime text2的snippet设置
查看>>
我的友情链接
查看>>
使用AsyncHttpClient碰到的问题及解决方法
查看>>
DHCP服务的基本配置
查看>>
_tkinter.TclError: no display name and no $DISPLAY
查看>>