成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

ReactNative之原生模塊開(kāi)發(fā)并發(fā)布--iOS篇

移動(dòng)開(kāi)發(fā)
前段時(shí)間做了個(gè)ReactNative的App,發(fā)現(xiàn)ReactNative中不少組件并不存在,所以還是需要自己對(duì)原生模塊進(jìn)行編寫(xiě)讓JS調(diào)用, 正是因?yàn)樵谶@個(gè)編寫(xiě)過(guò)程中遇到不少問(wèn)題,發(fā)覺(jué)了官網(wǎng)文檔中許多的不足。所以產(chǎn)生了寫(xiě)一個(gè)實(shí)踐教程的想法,最終有了這么一篇文章。

[[166181]]

前段時(shí)間做了個(gè)ReactNative的App,發(fā)現(xiàn)ReactNative中不少組件并不存在,所以還是需要自己對(duì)原生模塊進(jìn)行編寫(xiě)讓JS調(diào)用, 正是因?yàn)樵谶@個(gè)編寫(xiě)過(guò)程中遇到不少問(wèn)題,發(fā)覺(jué)了官網(wǎng)文檔中許多的不足。所以產(chǎn)生了寫(xiě)一個(gè)實(shí)踐教程的想法,最終有了這么一篇文章。

整篇文章主要以編寫(xiě)一個(gè)原生模塊為例子,來(lái)講述了我們?cè)诰帉?xiě)原生模塊所用到的一些知識(shí),并且在整個(gè)例子中,配有了完整的實(shí)踐代碼,方便大家理解并調(diào) 試。除了這些內(nèi)容,文章還講述了我們?nèi)绾螌⒆约壕帉?xiě)的原生模塊發(fā)布到npm上分享給別人使用。希望能夠給大家?guī)?lái)幫助,也希望大家將自己編寫(xiě)的原生模塊分 享出來(lái)。

示例代碼github地址:https://github.com/liuchungui/react-native-BGNativeModuleExample

準(zhǔn)備工作:

創(chuàng)建ReactNative工程

我們需要先創(chuàng)建一個(gè)ReactNative工程,使用如下命令創(chuàng)建。

  1. react native init TestProject 

創(chuàng)建好工程之后,我們使用xcode打開(kāi)TestProject/ios/下的iOS工程。

創(chuàng)建靜態(tài)庫(kù),并將這個(gè)靜態(tài)庫(kù)手動(dòng)鏈接到工程中

首先,我們?cè)谇懊鎰?chuàng)建的ReactNative工程下的node_modules創(chuàng)建一個(gè)文件夾react-native-BGNativeModuleExample,然后我們?cè)谛聞?chuàng)建的文件夾下再創(chuàng)建一個(gè)ios文件夾。

  1. $ cd TestProject/node_modules 
  2. $ mkdir react-native-BGNativeModuleExample 
  3. $ cd react-native-BGNativeModuleExample 
  4. $ mkdir ios 

然后,由于ReactNative的組件都是一個(gè)個(gè)靜態(tài)庫(kù),我們發(fā)布到npm給別人使用的話(huà),也需要建立靜態(tài)庫(kù)。我們使用Xcode建立靜態(tài)庫(kù),取 名為BGNativeModuleExample。建立之后,我們將創(chuàng)建的靜態(tài)庫(kù)中的文件全部copy到node_modules/react- native-BGNativeModuleExample/ios目錄下。

iOS文件目錄如下:

  1. |____BGNativeModuleExample 
  2. | |____BGNativeModuleExample.h 
  3. | |____BGNativeModuleExample.m 
  4. |____BGNativeModuleExample.xcodeproj 

最后,我們需要手動(dòng)將這個(gè)靜態(tài)庫(kù)鏈接到工程中。

1、使用xcode打開(kāi)創(chuàng)建的靜態(tài)庫(kù),添加一行Header Search Paths,值為$(SRCROOT)/../../react-native/React,并設(shè)置為recursive。

2、將BGNativeModuleExample靜態(tài)庫(kù)工程拖動(dòng)到工程中的Library中。 

3、選中 TARGETS => TestProject => Build Settings => Link Binary With Libraries,添加libBGNativeModuleExample.a這個(gè)靜態(tài)庫(kù) 

到此,我們準(zhǔn)備工作完成了。我們這里這么準(zhǔn)備是有用意的,那就是模擬npm鏈接的過(guò)程,建立好了環(huán)境,避免了發(fā)布到npm上后別人使用找不到靜態(tài)庫(kù)的問(wèn)題。

一、編寫(xiě)原生模塊代碼

1、創(chuàng)建原生模塊

選中我們創(chuàng)建的BGNativeModuleExample靜態(tài)庫(kù),然后在BGNativeModuleExample.h文件中導(dǎo)入RCTBridgeModule.h,讓BGNativeModuleExample類(lèi)遵循RCTBridgeModule協(xié)議。

  1. //BGNativeModuleExample.h文件的內(nèi)容如下 
  2. #import #import "RCTBridgeModule.h" 
  3. @interface BGNativeModuleExample : NSObject @end 

在BGNativeModuleExample.m文件中,我們需要實(shí)現(xiàn)RCTBridgeModule協(xié)議。為了實(shí)現(xiàn) RCTBridgeModule協(xié)議,我們的類(lèi)需要包含RCT_EXPORT_MODULE()宏。這個(gè)宏也可以添加一個(gè)參數(shù)用來(lái)指定在 Javascript中訪(fǎng)問(wèn)這個(gè)模塊的名字。如果不指定,默認(rèn)會(huì)使用這個(gè)類(lèi)的名字。

在這里,我們指定了模塊的名字為BGNativeModuleExample。

  1. RCT_EXPORT_MODULE(BGNativeModuleExample); 

實(shí)現(xiàn)了RCTBridgeModule協(xié)議之后,我們就可以在js中如下獲取到我們創(chuàng)建的原生模塊。

  1. import { NativeModules } from 'react-native'
  2. var BGNativeModuleExample = NativeModules.BGNativeModuleExample; 

需要注意的是,RCT_EXPORT_MODULE宏傳遞的參數(shù)不能是OC中的字符串。如果傳遞 @“BGNativeModuleExample",那么我們導(dǎo)出給JS的模塊名字其實(shí)是@"BGNativeModuleExample",使用 BGNativeModuleExample就找不到了。在這里,我們其實(shí)可以通過(guò)打印NativeModules來(lái)查找到我們創(chuàng)建的原生模塊。

2、為原生模塊添加方法

我們需要明確的聲明要給JS導(dǎo)出的方法,否則ReactNative不會(huì)導(dǎo)出任何方法。聲明通過(guò)RCT_EXPORT_METHOD()宏來(lái)實(shí)現(xiàn):

  1. RCT_EXPORT_METHOD(testPrint:(NSString *)name info:(NSDictionary *)info) { 
  2.   RCTLogInfo(@"%@: %@", name, info); 

在JS中,我們可以這樣調(diào)用這個(gè)方法:

  1. BGNativeModuleExample.testPrint("Jack", { 
  2.   height: '1.78m'
  3.   weight: '7kg' 
  4. }); 

3、參數(shù)類(lèi)型

RCT_EXPORT_METHOD()支持所有標(biāo)準(zhǔn)的JSON類(lèi)型,包括:

  • string (NSString)

  • number (NSInteger, float, double, CGFloat, NSNumber)

  • boolean (BOOL, NSNumber)

  • array (NSArray) 包含本列表中任意類(lèi)型

  • map (NSDictionary) 包含string類(lèi)型的鍵和本列表中任意類(lèi)型的值

  • function (RCTResponseSenderBlock)

除此以外,任何RCTConvert類(lèi)支持的的類(lèi)型也都可以使用(參見(jiàn)RCTConvert了解更多信息)。RCTConvert還提供了一系列輔助函數(shù),用來(lái)接收一個(gè)JSON值并轉(zhuǎn)換到原生Objective-C類(lèi)型或類(lèi)。

了解更多請(qǐng)點(diǎn)擊原生模塊

4、回調(diào)函數(shù)

警告:本章節(jié)內(nèi)容目前還處在實(shí)驗(yàn)階段,因?yàn)槲覀冞€并沒(méi)有太多的實(shí)踐經(jīng)驗(yàn)來(lái)處理回調(diào)函數(shù)。

回調(diào)函數(shù),在官方的文檔中是有上面的一個(gè)警告,不過(guò)在使用過(guò)程暫時(shí)未發(fā)現(xiàn)問(wèn)題。在OC中,我們添加一個(gè)getNativeClass方法,將當(dāng)前模塊的類(lèi)名回調(diào)給JS。

  1. RCT_EXPORT_METHOD(getNativeClass:(RCTResponseSenderBlock)callback) { 
  2.   callback(@[NSStringFromClass([self class])]); 

在JS中,我們通過(guò)以下方式獲取到原生模塊的類(lèi)名

  1. BGNativeModuleExample.getNativeClass(name => { 
  2.   console.log("nativeClass: ", name); 
  3. }); 

原生模塊通常只應(yīng)調(diào)用回調(diào)函數(shù)一次。但是,它們可以保存callback并在將來(lái)調(diào)用。這在封裝那些通過(guò)“委托函數(shù)”來(lái)獲得返回值的iOS API時(shí)最常見(jiàn)。

5、Promises

原生模塊還可以使用promise來(lái)簡(jiǎn)化代碼,搭配ES2016(ES7)標(biāo)準(zhǔn)的async/await語(yǔ)法則效果更佳。如果橋接原生方法的最后兩 個(gè)參數(shù)是RCTPromiseResolveBlock和RCTPromiseRejectBlock,則對(duì)應(yīng)的JS方法就會(huì)返回一個(gè)Promise對(duì) 象。

我們通過(guò)Promises來(lái)實(shí)現(xiàn)原生模塊是否會(huì)響應(yīng)方法,響應(yīng)則返回YES,不響應(yīng)則返回一個(gè)錯(cuò)誤信息,代碼如下:

  1. RCT_REMAP_METHOD(testRespondMethod, 
  2.                  name:(NSString *)name 
  3.                  resolver:(RCTPromiseResolveBlock)resolve 
  4.                  rejecter:(RCTPromiseRejectBlock)reject) { 
  5.   if([self respondsToSelector:NSSelectorFromString(name)]) { 
  6.     resolve(@YES); 
  7.   } 
  8.   else { 
  9.     reject(@"-1001", @"not respond this method", nil); 
  10.   } 

在JS中,我們有兩種方式調(diào)用,第一種是通過(guò)then....catch的方式:

  1. BGNativeModuleExample.testRespondMethod("dealloc"
  2.     .then(result => { 
  3.       console.log("result is ", result); 
  4.     }) 
  5.     .catch(error => { 
  6.       console.log(error); 
  7.     }); 

第二種是通過(guò)try...catch來(lái)調(diào)用,與第一種相比,第二種會(huì)報(bào)警告”Possible Unhandled Promiss Rejection (id:0)“。

  1. async testRespond() { 
  2. try { 
  3.   var result = BGNativeModuleExample.testRespondMethod("hell"); 
  4.   if(result) { 
  5.     console.log("respond this method"); 
  6.   } 
  7. catch (e) { 
  8.   console.log(e); 
  9.   } 

注意: 如果使用Promiss我們不需要參數(shù),則在OC去掉name那一行就行了;如果需要多個(gè)參數(shù),在name下面多加一行就行了,注意它們之間不需要添加逗號(hào)。

6、多線(xiàn)程

我們這里操作的模塊沒(méi)有涉及到UI,所以專(zhuān)門(mén)建立一個(gè)串行的隊(duì)列給它使用,如下:

  1. return dispatch_queue_create("com.liuchungui.demo", DISPATCH_QUEUE_SERIAL); 

注意: 在模塊之間共享分發(fā)隊(duì)列 

methodQueue方法會(huì)在模塊被初始化的時(shí)候被執(zhí)行一次,然后會(huì)被React Native的橋接機(jī)制保存下來(lái),所以你不需要自己保存隊(duì)列的引用,除非你希望在模塊的其它地方使用它。但是,如果你希望在若干個(gè)模塊中共享同一個(gè)隊(duì)列, 則需要自己保存并返回相同的隊(duì)列實(shí)例;僅僅是返回相同名字的隊(duì)列是不行的。

更多線(xiàn)程的操作細(xì)節(jié)可以參考:http://reactnative.cn/docs/0.24/native-modules-ios.html#content

7、導(dǎo)出常量

原生模塊可以導(dǎo)出一些常量,這些常量在JavaScript端隨時(shí)都可以訪(fǎng)問(wèn)。用這種方法來(lái)傳遞一些靜態(tài)數(shù)據(jù),可以避免通過(guò)bridge進(jìn)行一次來(lái)回交互。

OC中,我們實(shí)現(xiàn)constantsToExport方法,如下:

  1. - (NSDictionary *)constantsToExport { 
  2.   return @{ @"BGModuleName" : @"BGNativeModuleExample"
  3.             TestEventName: TestEventName 
  4.             }; 

JS中,我們打印一下這個(gè)常量

  1. console.log("BGModuleName value is ", BGNativeModuleExample.BGModuleName); 

但是注意這個(gè)常量?jī)H僅在初始化的時(shí)候?qū)С隽艘淮危约词鼓阍谶\(yùn)行期間改變constantToExport返回的值,也不會(huì)影響到JavaScript環(huán)境下所得到的結(jié)果。

8、給JS發(fā)送事件

即使沒(méi)有被JS調(diào)用,本地模塊也可以給JS發(fā)送事件通知。最直接的方式是使用eventDispatcher。

在這里,我們?yōu)榱四軌蚪邮盏绞录覀冮_(kāi)一個(gè)定時(shí)器,每一秒發(fā)送一次事件。

  1. #import "BGNativeModuleExample.h" 
  2. #import "RCTEventDispatcher.h" 
  3. @implementation BGNativeModuleExample 
  4. @synthesize bridge = _bridge; 
  5. - (instancetype)init { 
  6.   if(self = [super init]) { 
  7.     [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(sendEventToJS) userInfo:nil repeats:YES]; 
  8.   } 
  9.   return self; 
  10. - (void)receiveNotification:(NSNotification *)notification { 
  11.   [self.bridge.eventDispatcher sendAppEventWithName:TestEventName body:@{@"name": @"Jack"}]; 
  12. @end 

在JS中,我們這樣接收事件

  1. NativeAppEventEmitter.addListener(BGNativeModuleExample.TestEventName, info => { 
  2.       console.log(info); 
  3.     }); 

注意: 編寫(xiě)OC代碼時(shí),需要添加@synthesize bridge = _bridge;,否則接收事件的時(shí)候就會(huì)報(bào)Exception -[BGNativeModuleExample brige]; unrecognized selector sent to instance的錯(cuò)誤。

上面原生代碼就編寫(xiě)好了,主要以代碼實(shí)踐為主,彌補(bǔ)官方文檔中的一些不足,如果要需要了解更多的原生模塊封裝的知識(shí),可以參考原生模塊,也可以參考官方的源代碼。

二、發(fā)布上線(xiàn)

我們按照上面步驟編寫(xiě)好原生模塊之后,接下來(lái)將我們寫(xiě)的原生模塊發(fā)布到npm。

1、我們需要?jiǎng)?chuàng)建github倉(cāng)庫(kù)

在github上創(chuàng)建一個(gè)倉(cāng)庫(kù)react-native-BGNativeModuleExample,然后關(guān)聯(lián)到我們前面創(chuàng)建的react-native-BGNativeModuleExample目錄

  1. $ cd TestProject/node_modules/react-native-BGNativeModuleExample 
  2. $ git init . 
  3. $ git remote add origin https://github.com/liuchungui/react-native-BGNativeModuleExample.git 

2、我們需要?jiǎng)?chuàng)建原生模塊的入口文件

我們需要在react-native-BGNativeModuleExample目錄下創(chuàng)建一個(gè)index.js,它是整個(gè)原生模塊的入口,我們這里只是將原生進(jìn)行導(dǎo)出。

  1. //index.js 
  2. import React, { NativeModules } from 'react-native'
  3. module.exports = NativeModules.BGNativeModuleExample; 

3、發(fā)布到npm

在發(fā)布到npm之前,我們需要?jiǎng)?chuàng)建一個(gè)package.json文件,這個(gè)文件包含了module的所有信息,比如名稱(chēng)、版本、描述、依賴(lài)、作者、 license等。 我們?cè)趓eact-native-BGNativeModuleExample根目錄下使用npm init命令來(lái)創(chuàng)建package.json,系統(tǒng)會(huì)提示我們輸入所需的信息,不想輸入的直接按下Enter跳過(guò)。

  1. $ npm init 
  2. This utility will walk you through creating a package.json file. 
  3. It only covers the most common items, and tries to guess sensible defaults. 
  4. See `npm help json` for definitive documentation on these fields 
  5. and exactly what they do
  6. Use `npm install  --save` afterwards to install a package and 
  7. save it as a dependency in the package.json file. 
  8. Press ^C at any time to quit. 
  9. name: (react-native-BGNativeModuleExample) 

輸入完成之后,系統(tǒng)會(huì)要我們確認(rèn)文件的內(nèi)容是否有誤,如果沒(méi)有問(wèn)題直接輸入yes,那么package.json就創(chuàng)建好了。 我這里創(chuàng)建的package.json文件如下:

  1.   "name""react-native-nativemodule-example"
  2.   "version""1.0.0"
  3.   "description"""
  4.   "main""index.js"
  5.   "scripts": { 
  6.     "test""echo \"Error: no test specified\" && exit 1" 
  7.   }, 
  8.   "repository": { 
  9.     "type""git"
  10.     "url""git+https://github.com/liuchungui/react-native-BGNativeModuleExample.git" 
  11.   }, 
  12.   "author"""
  13.   "license""ISC"
  14.   "bugs": { 
  15.     "url""https://github.com/liuchungui/react-native-BGNativeModuleExample/issues" 
  16.   }, 
  17.   "homepage""https://github.com/liuchungui/react-native-BGNativeModuleExample#readme" 

如果我們編寫(xiě)的原生模塊依賴(lài)于其他的原生模塊,我們需要在package.json添加依賴(lài)關(guān)系,我們這里由于沒(méi)有相關(guān)依賴(lài),所以不需要添加:

  1. "dependencies": { 

初始化完package.json,我們就可以發(fā)布到npm上面了。

如果沒(méi)有npm的賬號(hào),我們需要注冊(cè)一個(gè)賬號(hào),這個(gè)賬號(hào)會(huì)被添加到npm本地的配置中,用來(lái)發(fā)布module用。

  1. $ npm adduser 
  2. Username: your name 
  3. Password: your password 
  4. Email: yourmail@gmail.com 

成功之后,npm會(huì)把認(rèn)證信息存儲(chǔ)在~/.npmrc中,并且可以通過(guò)以下命令查看npm當(dāng)前使用的用戶(hù):

  1. $ npm whoami 

以上完成之后,我們就可以進(jìn)行發(fā)布了。

  1. $npm publish 
  2. + react-native-nativemodule-example@1.0.0 

到這里,我們已經(jīng)成功把module發(fā)布到了npmjs.org。當(dāng)然,我們也別忘記將我們的代碼發(fā)布到github。

  1. $ git pull origin master 
  2. $ git add . 
  3. $ git commit -m 'add Project' 
  4. $ git push origin master 

有時(shí)候,有些文件沒(méi)必要發(fā)布,例如Example文件,我們就可以通過(guò).npmignore忽略它。例如我這里.npmignore文件內(nèi)容如下:

  1. Example/ 
  2. .git 
  3. .gitignore 
  4. .idea 

這樣的話(huà),我們npm進(jìn)行發(fā)布的時(shí)候,就不會(huì)將Example發(fā)布到npm上了。

4、添加Example,測(cè)試是否可用,添加README

我們?cè)趓eact-native-BGNativeModuleExample目錄下創(chuàng)建一個(gè)Example的ReactNative工程,并且通 過(guò)rnpm install react-native-nativemodule-example命令安裝我們發(fā)布的react-native-nativemodule- example模塊。

  1. $ rnpm install react-native-nativemodule-example 
  2. TestProject@0.0.1 /Users/user/github/TestProject 
  3. └── react-native-nativemodule-example@1.0.0 
  4. rnpm-link info Linking react-native-nativemodule-example ios dependency 
  5. rnpm-link info iOS module react-native-nativemodule-example has been successfully linked 
  6. rnpm-link info Module react-native-nativemodule-example has been successfully installed & linked 

上面提示安裝并且link成功,我們就可以在js中進(jìn)行使用了。

  1. import BGNativeModuleExample from 'react-native-nativemodule-example'
  2. BGNativeModuleExample.testPrint("Jack", { 
  3.     height: '1.78m'
  4.     weight: '7kg' 
  5. }); 

5、我們?cè)诎l(fā)布上線(xiàn)之后還需要編寫(xiě)README文件。

README文件是非常重要的,如果沒(méi)有README文件,別人看到我們的原生組件,根本就不知道我們這個(gè)組件是用來(lái)干啥的。所以,我們很有必要添加一個(gè)README文件,這個(gè)文件需要告訴別人我們這個(gè)原生組件是干什么的、如何安裝、API、使用手冊(cè)等等。

6、原生模塊升級(jí),發(fā)布新版本

當(dāng)我們添加新代碼或者修復(fù)bug后,需要發(fā)布新的版本,我們只需要修改package.json文件中的version的值就行了,然后使用npm publish進(jìn)行發(fā)布。

總結(jié)

本篇文章主要分成兩個(gè)部分,一是講述了編寫(xiě)原生模塊的知識(shí),二是將我們編寫(xiě)的內(nèi)容發(fā)布到npm上。

參考

如何發(fā)布Node模塊到NPM社區(qū)

原生模塊

責(zé)任編輯:倪明 來(lái)源: 劉春桂的博客
相關(guān)推薦

2016-08-23 13:53:25

iOS開(kāi)發(fā)邏輯

2011-08-03 13:43:50

iOS程序 打包 發(fā)布

2023-12-26 10:04:29

Electron應(yīng)用開(kāi)發(fā)框架

2016-12-22 19:53:46

AndroidAPPReactNative

2016-11-23 16:48:20

react-nativandroidjavascript

2014-07-23 13:17:53

iOSUITextField

2014-07-21 14:49:35

iOSUILabel

2015-09-22 09:50:36

FacebookAndroid

2015-09-11 09:15:32

RyuSDN

2015-03-30 12:13:23

React NativiOS

2011-08-02 11:07:42

iOS開(kāi)發(fā) UIWebView

2017-02-15 09:25:36

iOS開(kāi)發(fā)MQTT

2011-08-11 16:50:04

iOSTwitter

2015-10-10 16:02:36

React NativAndroid

2011-08-15 11:13:06

IOS開(kāi)發(fā)并發(fā)Dispatch Qu

2011-04-18 10:16:30

WEB高性能

2022-10-27 18:03:04

GogRPC云原生

2013-04-11 16:08:50

iOS開(kāi)發(fā)技巧積累

2013-07-29 04:51:41

iOS開(kāi)發(fā)iOS開(kāi)發(fā)學(xué)習(xí)file列表查看
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲国产成人精品女人 | 91中文视频| 亚洲成人三区 | 91看片| 久久精品国产99国产精品 | 久久国产成人午夜av影院武则天 | 精品久久久久久久久久久久久久 | 欧美国产视频 | 中文字幕av亚洲精品一部二部 | 国产精品99久久久久久久久久久久 | 亚洲男人天堂网 | 一区二区三区在线 | 午夜黄色影院 | 国产高清一二三区 | 四虎影音 | 亚洲欧美激情精品一区二区 | 二区三区av| 日本又色又爽又黄又高潮 | 在线观看欧美一区 | 久久精品日产第一区二区三区 | 久草免费在线视频 | www国产亚洲精品久久网站 | 国产精品一区二区久久 | 99re热这里只有精品视频 | 色综合一区二区 | 日本久久精品 | 91看片网| 男人天堂久久 | 国产亚洲精品精品国产亚洲综合 | 91天堂网 | 99精品国产一区二区三区 | 国产精品久久久久永久免费观看 | 成人在线观看免费观看 | 91精品国产高清一区二区三区 | 久久久影院 | 高清18麻豆 | 国产精品久久久久一区二区三区 | 涩涩视频网 | 久久视频精品 | 日韩电影中文字幕 | 日韩精品|