React Native 調(diào)用原生Android/iOS代碼實(shí)現(xiàn)撥號(hào)功能

React Native 調(diào)用原生Android、iOS模塊實(shí)現(xiàn)撥號(hào)功能

一 前言

由于前幾個(gè)月公司2.0項(xiàng)目開(kāi)發(fā)技術(shù)選型為React Native,技術(shù)部相關(guān)人員開(kāi)始學(xué)習(xí)React Native相關(guān)的技術(shù)智政,筆者是一名Android開(kāi)發(fā)者掏缎,下文所描述的React Native調(diào)用Android/iOS模塊中關(guān)于iOS的部分如有誤的地方阐斜,請(qǐng)指出衫冻。為了讓從Android或iOS學(xué)習(xí)React Native的同志更加清楚的了解另一移動(dòng)端,筆者盡可能寫(xiě)的詳細(xì)點(diǎn)谒出。

二 效果

下面兩張圖分別為iOS和Android上效果圖隅俘,其中iOS效果圖中點(diǎn)擊電話號(hào)碼會(huì)打印log,并不會(huì)調(diào)起iOS撥號(hào)界面笤喳,因?yàn)閕OS模擬器不支持此功能为居,所以要想看效果只能用真機(jī)查看。這里打印log是為了證明React Native成功調(diào)起了原生iOS模塊功能莉测。

react native調(diào)用iOS
React Native調(diào)用Android

三 實(shí)現(xiàn)方案

關(guān)于調(diào)用撥號(hào)功能以及調(diào)用瀏覽器颜骤、短信、郵箱等功能捣卤,可有兩種實(shí)現(xiàn)方案忍抽。

一種是按照React Native提供的調(diào)用原生的過(guò)程方案來(lái)調(diào)用,這種適合大部分React Native調(diào)用原生功能的需求董朝,掌握這種后鸠项,基本以后再有調(diào)用原生需求即可按照此過(guò)程方案解決,此文也會(huì)選用這種方案進(jìn)行描述子姜。

另一種是React Native幫我們封裝的Linking模塊可以實(shí)現(xiàn)這類的需求祟绊,這種相比上一種來(lái)說(shuō)相對(duì)簡(jiǎn)單,主要適用于調(diào)用原生的電話哥捕、短信牧抽、郵箱、瀏覽器等功能遥赚。

四 實(shí)現(xiàn)原生Android模塊

1.在自己新建的Reacat Native項(xiàng)目中android/app/src/main/java/xxx(項(xiàng)目包名)/ 目錄下(為了和其他文件分離扬舒,筆者又在此目錄下新建一個(gè)native文件夾),需要新建一個(gè)java類文件凫佛,例如文件名為CallPhoneModule.java,這個(gè)java類一定要繼承RN提供的ReactContextBaseJavaModule抽象類,然后實(shí)現(xiàn)其構(gòu)造函數(shù)讲坎,其中的參數(shù)要為ReactApplicationContext reactContext。

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

2.然后實(shí)現(xiàn)NativeModule中定義的getName()方法愧薛,返回一個(gè)String類型字符串晨炕,這個(gè)返回結(jié)果將要在JavaScript中使用,例如返回“CallPhoneModule”毫炉,則可以在JavaScript中通過(guò)React.NativeModules.CallPhoneModule調(diào)用瓮栗。注意,如果返回的字符串中有RCT前綴,則會(huì)自動(dòng)移除RCT前綴费奸。例如返回“RCTCallPhoneModule”,則在JavaScript中依然可以通過(guò)React.NativeModules.CallPhoneModule調(diào)用鲸郊。CallPhoneModule繼承ReactContextBaseJavaModule,ReactContextBaseJavaModule繼承BaseJavaModule货邓,BaseJavaModule實(shí)現(xiàn)了NativeModule接口,這是CallPhoneModule與NativeModule的關(guān)系四濒。

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

3.然后在CallPhoneModule類中寫(xiě)一個(gè)方法换况,這個(gè)方法提供給JavaScript調(diào)用,例如方法名為callPhone盗蟆,里面?zhèn)鬟fString類型參數(shù)(非必須)戈二,特別的這個(gè)方法要使用@ReactMethod注解,以及返回類型必須為void喳资。然后在callPhone方法中寫(xiě)入要實(shí)現(xiàn)的功能觉吭,這里寫(xiě)入了撥號(hào)功能的實(shí)現(xiàn)。

 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.新建一個(gè)java類文件仆邓,例如文件名為CallPhoneReactPackage.java鲜滩,這個(gè)類必須實(shí)現(xiàn)ReactPackage接口,然后實(shí)現(xiàn)createViewManagers节值、createNativeModules兩個(gè)方法徙硅,特別的要在createNativeModules方法的返回值中add進(jìn)剛才新建的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模塊書(shū)寫(xiě)完畢。關(guān)于JavaScript調(diào)用原生Android模塊代碼會(huì)在文末和調(diào)用原生iOS一起寫(xiě)出匿乃。

修改后的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

五 實(shí)現(xiàn)原生iOS模塊

1.在自己新建的Reacat Native項(xiàng)目中ios/xxx(項(xiàng)目包名)/ 目錄下桩皿,需要新建一個(gè)后綴為m和一個(gè)后綴為h的文件。為了和其他文件分離以及和Android保持一致幢炸,筆者又在此目錄下新建一個(gè)native文件夾泄隔。在Xcode的此文件夾上右鍵New File,然后在彈出的頁(yè)面中Cocoa Touch Class選項(xiàng)輸入文件名阳懂,這樣會(huì)建立出相同文件名的m和h文件梅尤。如果New File時(shí),分別選擇Objective-C File和Header File岩调,則這兩個(gè)文件名要相同巷燥。例如文件名稱為CallPhoneModuleIos。

2.在CallPhoneModuleIos.h文件中号枕,類要實(shí)現(xiàn)RN提供的RCTBridgeModule協(xié)議缰揪。RCT是ReaCT的縮寫(xiě),React Native中Object-C相關(guān)的命名均以RCT開(kāi)頭。RCTBridgeModule是定義好的protocol钝腺,實(shí)現(xiàn)該協(xié)議的類抛姑,會(huì)自動(dòng)注冊(cè)到Object-C對(duì)應(yīng)的Bridge中。Object-C Bridge上層負(fù)責(zé)與Object-C通信艳狐,下層負(fù)責(zé)和JavaScript Bridge通信定硝,而JavaScript Bridge負(fù)責(zé)和JavaScript通信。這樣,通過(guò)Object-C Bridge和JavaScript Bridge就可以實(shí)現(xiàn)JavaScript和Object-C的相互調(diào)用毫目。

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()宏,作用是自動(dòng)注冊(cè)一個(gè)module镀虐。這個(gè)宏可以添加一個(gè)參數(shù)箱蟆,用來(lái)指定在JavaScript調(diào)用這個(gè)模塊的名字,類似于上文中說(shuō)的getName()方法刮便。如果不添加這個(gè)參數(shù)空猜,則默認(rèn)就是這個(gè)類的名字。

4.然后需要在此類中寫(xiě)一個(gè)方法恨旱,提供給RN調(diào)用辈毯,方法通過(guò)RCT_EXPORT_METHOD()宏來(lái)實(shí)現(xiàn)。

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);
  //去掉注釋漓摩,下面代碼就是實(shí)現(xiàn)撥號(hào)功能代碼,但還未真機(jī)測(cè)試
//  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代碼書(shū)寫(xiě)完成管毙,現(xiàn)在即將開(kāi)始調(diào)用。

六 React Native調(diào)用Android桌硫、iOS原生模塊

為了在JavaScript端同時(shí)訪問(wèn)Android夭咬、iOS原生模塊更加方便,筆者把原生模塊的調(diào)用封裝在一個(gè)JavaScript文件中铆隘,例如文件名為CallPhone.js,這樣在需要調(diào)用的地方直接調(diào)用此JavaScript文件既可卓舵,同時(shí)在此文件中,處理好Android膀钠、iOS掏湾、Web(若有)的分別調(diào)用。

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') {
    //暫未實(shí)現(xiàn)web功能  
}
export default module;
CallPhone

然后在JavaScript文件中這樣調(diào)用:

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

到這里肿嘲,整篇文章就結(jié)束了融击,疑問(wèn)、建議或者指教歡迎討論雳窟。

七 參考資料

native-modules-ios
native-modules-android

原創(chuàng)文章尊浪,轉(zhuǎn)載請(qǐng)注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拇涤,隨后出現(xiàn)的幾起案子捣作,更是在濱河造成了極大的恐慌,老刑警劉巖鹅士,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件券躁,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡掉盅,警方通過(guò)查閱死者的電腦和手機(jī)嘱朽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怔接,“玉大人,你說(shuō)我怎么就攤上這事稀轨《笃辏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵奋刽,是天一觀的道長(zhǎng)瓦侮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)佣谐,這世上最難降的妖魔是什么肚吏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮狭魂,結(jié)果婚禮上罚攀,老公的妹妹穿的比我還像新娘。我一直安慰自己雌澄,他們只是感情好斋泄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著镐牺,像睡著了一般炫掐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上睬涧,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天募胃,我揣著相機(jī)與錄音,去河邊找鬼畦浓。 笑死痹束,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宅粥。 我是一名探鬼主播参袱,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了抹蚀?” 一聲冷哼從身側(cè)響起剿牺,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎环壤,沒(méi)想到半個(gè)月后晒来,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡郑现,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年湃崩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片接箫。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡攒读,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辛友,到底是詐尸還是另有隱情薄扁,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布废累,位于F島的核電站邓梅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏邑滨。R本人自食惡果不足惜日缨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掖看。 院中可真熱鬧匣距,春花似錦、人聲如沸哎壳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)耳峦。三九已至恩静,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹲坷,已是汗流浹背驶乾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留循签,地道東北人级乐。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像县匠,于是被迫代替她去往敵國(guó)和親风科。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撒轮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容