React Native is an Objective-C application framework that bridges JavaScript applications running in the Jscore JavaScript engine to iOS and Android native APIs.

In theory,you write your application logic in JSX and ES6/7 and transpile it to JavaScript,and the application framework loads all that as a bundle.

In practice,you will want to expose your own custom native code to your JavaScript application. You may want to provide access to 3rd party library APIs or iOS framework features that aren’t exposed (yet) by React Native.

React Native is written in Objective-C,but we can write modules in Swift and expose them to our applications. The documentation on the React Native site briefly talks about “Exporting Swift,” but is thin on the details of doing much of anything in Swift. In this article,we’ll do a deeper dive into interfacing Swift to JavaScript.

It is assumed you already have React Native and its prerequisites installed on your system. You can find the code used in this article in this GitHub repository:https://github.com/ModusCreateOrg/swift-modules-for-react-native.

Create a React Native project and open it in Xcode:

$ react-native init SwiftBridge && cd 
$ ls
android/         index.iosjs     node_modules
indexandroidjs ios             packagejson
$ ls ios
SwiftBridge         xcodeproj SwiftBridgeTests
$ open ios/xcodeproj

Click the run button in Xcode and see that the project builds and runs.

At this point,we know that if the application fails to compile or run,it is something we’ve done to the project at fault.

We’ll start by implementingthe CalendarManager sample code from the React Native docsand see that it works.

First,we need to add our Swift source file. Right click on SwiftBridge and select “New File…”:

Choose iOS and Swift File from the “Choose template” dialog:

Choose a filename for the file:

You will be asked if you would like to configure an Objective-C bridging header. We will need this,so click on the Create button:

We copy the CalendarManager.swift example code from the React Native docs page and paste it into our CalendarManager.swift file:

//
//  CalendarManager.swift//  SwiftBridge//  Created by Michael Schwartz on 12/11/15.//  Copyright © 2015 Facebook. All rights reserved.

importFoundation

// CalendarManager.swift

@objc(CalendarManager)
class:NSObject{
  
  @objc func addEvent(nameString, location dateNSNumber->Void
    // Date is ready to use!
  }
  
}

Unfortunately,we have to provide an Objective-C file that exposes our Swift to the React Native Objective-C framework. Create the file “CalendarManageBridge.m” by selecting “New File” as before and choose Objective-C File this time:

This time you will be presented with a “Choose options for your new file” dialog:

Enter “CalendarManagerBridge” in the File text field and click the Next button. Click the Create button on the next dialog:

The file is added to your project.

Copy and paste the code from the React Native docs page to this file:

//  CalendarManagerBridge.m#import 
 
  
  
  // CalendarManagerBridge.m
  
  #import "RCTBridgeModule.h"
  
   
  
  @interface
  
   RCT_EXTERN_MODULE
  
  (
  
  CalendarManager
  
   
  
  NSObject
  
  )
  
   RCT_EXTERN_METHOD
  
  (
  
  addEvent
  
  :(
  
  NSString
  
   
  
  *)
  
  name location
  
  location date
  
  NSNumber
  
  date
  
  @end
 
 

Finally,we edit the SwiftBridge-Bridging-Header.h file and copy the two lines from the React Native docs page there:

//  Use this file to import your target's public headers that you would like to expose to Swift.// CalendarManager-Bridging-Header.h#import "RCTBridgeModule.h"

Click on the run button in Xcode again and the project should run. If not,you did something wrong in the above steps.

varReact= require(‘reactnative’); // after this line consoledirReact.NativeModules); // ← add this line

When we run the project from Xcode with this line,we will get a red screen error:

It seems console.dir() is only present if we’re debugging via Chrome. Click the Dismiss (ESC) link on the red screen,then from the Simulator’s Hardware menu,choose Shake Gesture and choose “Debug in Chrome” from the action sheet that appears in the emulator window:

You should see a new window or tab in Chrome that looks something like this:

After hitting Command-Shift-J as the page suggests,you should see something like this:

Note that the console.dir() did work and you can expand the Object to see that our React.NativeModule.CalendarManager object is exposed to JavaScript and it contains the addEvent() method as we expect.

Let’s implement some code in the addEvent() method to see that we can call it from JavaScript and access the arguments passed to Swift. Edit CalendarManager.swift so it looks like this:

    NSLog("%@ %@ %S" nameAll that’s really changed is the NSLog() call to dump the passed variables. Let’s also add a call to the addEvent() method to index.ios.js,just after the console.dir(): 
addEvent(‘One’,125);">‘Two 3);

When we run this,and the application crashes. There is an error reported in both Chrome Dev Tools and Xcode and in the simulator.

Note that the NSLog() did work,but the React Native framework displayed the red screen.

The fix for this is to add “nonnull” to the CalendarManagerBridge.m file:

RCT_EXTERN_METHOD
:(NSString*)name locationlocation date:(nonnull NSNumberdate)

With this change,the app works without any errors. We can also see in the Xcode console the NSLog() output:

(Note: I created a GitHub issue about this problem with the React Native documentation page and it has been fixed).

We have verified we can access the arguments passed to our Swift method from JavaScript.

We cannot simply return values to JavaScript because React Native’s JavaScript/Native bridge is asynchronous. That is,you have to implement your Swift method with a callback parameter and call it with a callback function from JavaScript,or you may implement events.

Let’s examine the callback mechanism first. Change the RCT_EXTERN_METHOD line in CalendarManagerBridge.m to read:

date callbackRCTResponseSenderBlockcallbackThis adds a 4th parameter to the method,a callback function. In CalendarManager.swift,we need to alter the the addEvent() method: 
 callbackNSObject()
 
 "%@ %@ %@"
 callback[[
   "name""location""date" date
 ]])
What this version of addEvent() does is call the callback() method with a JavaScript Object that has the argument names/values as key/value pairs. In Swift,we create an NSObject with the [ key: value ] syntax. The argument to the callback from Swift is an array of argument values. In this case,we have just the one Object. 

We need to modify the JavaScript code in index.ios.js to pass a callback. It should look like this:

"One"
"Two"functiono consolelogInCallback});

When we run this version of the code in the simulator,this is displayed in the JavaScript debugger console:

In order to use events,we need to modify the ‘CalendarManager-Bridging-Header.h’ file to import additional headers from React Native. The file should read:



#import "RCTBridge.h"#import "RCTBridgeModule.h"#import "RCTEventDispatcher.h"

An RCTBridge instance contains an eventDispatcher that we can use to send events to JavaScript from Swift. In order to get this instance,we can have one synthesized for us in our CalendarManager class. We can also verify that it is synthesized by using NSLog() to dump its value.

Modify the class’ code in CalendarManager.swift so it looks like this:

  
   bridgeRCTBridge!// this is synthesized

  "Bridge: %@"selfbridge
    callback
       date
      There is the bridge member that will be synthesized and in the addEvent() method there is a call to NSLog() to print the value of the bridge. The value printed should be some hex number that’s the address of the bridge instance. 

When we run the code,we can see that the bridge member is synthesized:

Note that the code uses NSLog() instead of print(). NSLog is synchronized and works better with threading. It also prints a timestamp and prints to the device console when running on device.

Ultimately debug logging should be wrapped by some other means so the printing can be disabled or directed as you want.

Modify the CalenderManager class one more time so it looks like this:

    
let ret []([ret])eventDispatchersendAppEventWithName"EventReminder" body retThe sendAppEventWithName() method takes an event name and an arbitrary object that is sent to the JavaScript event handler. In the code above,we’re assigning the NSObject with arguments as key/value pairs to a variable and using it to pass to both the callback() and the event argument.

Modify the JavaScript code near the top of index.ios.js so it reads:

'react-native'
subscription NativeAppEventEmitteraddListener 'EventReminder' reminder=> consoleEVENT’)'name: '+ reminder'location: 'location'date: ' 'In Callback'})

We’re really just adding the subscription logic before calling addEvent(). When we run this version of the code,we see the expected output in the Chrome console:

func constantsToExportreturn"x"1"y"2"z""Arbitrary string"When we run the project and expand the first Object printed in the Chrome console,we see our constants:

In conclusion,we now have patterns to interface Swift native code to our JavaScript in React Native. From here we can implement our application logic in either language,as appropriate.


From: http://moduscreate.com/swift-modules-for-react-native/

Swift Modules for React Native的更多相关文章

  1. ios – React native链接到另一个应用程序

    如果是错误的,有人知道如何调用正确的吗?

  2. ios – React Native – 在异步操作后导航

    我正在使用ReactNative和Redux开发移动应用程序,我正面临着软件设计问题.我想调用RESTAPI进行登录,如果该操作成功,则导航到主视图.我正在使用redux和thunk所以我已经实现了异步操作,所以我的主要疑问是:我应该把逻辑导航到主视图?我可以直接从动作访问导航器对象并在那里执行导航吗?.我对组件中的逻辑没有信心.似乎不是一个好习惯.有没有其他方法可以做到这一点?

  3. 在ios中使用带有React Native(0.43.4)的cocoapods的正确方法是什么?

    我已经挖掘了很多帖子试图使用cocoapods为本地ios库设置一个反应原生项目,但我不可避免地在#import中找到了丢失文件的错误.我的AppDelegate.m文件中的语句.什么是使用反应原生的可可豆荚的正确方法?在这篇文章发表时,我目前的RN版本是0.43.4,而我正在使用Xcode8.2.1.这是我的过程,好奇我可能会出错:1)

  4. ios – React Native WebView滚动行为无法按预期工作

    如何确保滚动事件的行为与ReactNative应用程序中的浏览器相同?

  5. ios – React Native – BVLinearGradient – 找不到’React/RCTViewManager.h’文件

    谢谢.解决方法几天前我遇到了完全相同的问题.问题是在构建应用程序时React尚未链接.试试这个:转到Product=>Scheme=>管理方案…=>点击你的应用程序Scheme,然后点击Edit=>转到Build选项卡=>取消选中ParallelizeBuild然后点击标志添加目标=>搜索React,选择第一个名为React的目标,然后单击Add然后在目标列表中选择React并将其向上拖动到该列表中的第一个.然后转到Product=>再次清理并构建项目.这应该有所帮助.

  6. ios – React Native – NSNumber无法转换为NSString

    解决方法在你的fontWeight()函数中也许变成:

  7. ios – React native error – react-native-xcode.sh:line 45:react-native:command not found命令/ bin/sh失败,退出代码127

    尝试构建任何(新的或旧的)项目时出现此错误.我的节点是版本4.2.1,react-native是版本0.1.7.我看过其他有相同问题的人,所以我已经更新了本机的最新版本,但是我仍然无法通过xcode构建任何项目.解决方法要解决此问题,请使用以下步骤:>使用节点版本v4.2.1>cd进入[你的应用]/node_modules/react-native/packager>$sh./packager.s

  8. 反应原生 – 如何通过Xcode构建React Native iOS应用程序到设备?

    我试图将AwesomeProject应用程序构建到设备上.构建成功并启动屏幕显示,但后来我看到一个红色的“无法连接到开发服务器”屏幕.它表示“确保节点服务器正在运行–从Reactroot运行”npmstart“.看起来节点服务器已经运行,因为当我做npm启动时,我收到一个EADDRINUSE消息,表示该端口已经在使用.解决方法从设备访问开发服务器您可以使用开发服务器快速迭代设备.要做到这一点,你的

  9. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  10. 如何为iOS的React Native设置分析

    所以我已经完成了一个针对iOS的ReactNative项目,但是我想在其中分析.我尝试了react-native-google-analytics软件包,但是问题阻止了它的正常工作.此外,react-native-cordova-plugin软件包只适用于Android,因此插入Cordova插件进行分析的能力现在已成为问题.我也没有Swift/ObjectiveC的经验,所以将完全失去GA的插入.有没有人有任何建议如何连接GoogleAnalytics的ReactNativeforiOS?

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部