纯用Swift开发React Native应用程序

16

我使用以下命令创建了我的第一个React Native应用。

react-native init PropertyFinder

这创建了一个使用Objective-C编写的iOS项目。问题是我不懂Objective-C,但我熟悉Swift。

这个代码片段展示了如何将React组件链接到Swift项目。 但是否有一种方法可以直接使用Swift语言创建项目?

6个回答

17

这篇优秀的文章帮助我解决了问题。

解决方案

  1. 添加桥接头文件

解决方案

  1. 添加桥接头文件
#import "RCTBridgeModule.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "RCTRootView.h"
#import "RCTUtils.h"
#import "RCTConvert.h"
  1. 添加AppDelegate.Swift文件
var bridge: RCTBridge!

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    /**
     * Loading JavaScript code - uncomment the one you want.
     *
     * OPTION 1
     * Load from development server. Start the server from the repository root:
     *
     * $ npm start
     *
     * To run on device, change `localhost` to the IP address of your computer
     * (you can get this by typing `ifconfig` into the terminal and selecting the
     * `inet` value under `en0:`) and make sure your computer and iOS device are
     * on the same Wi-Fi network.
     */

    let jsCodeLocation = NSURL(string: "http://localhost:8081/index.ios.bundle?platform=ios&dev=true")

    /**
     * OPTION 2
     * Load from pre-bundled file on disk. The static bundle is automatically
     * generated by "Bundle React Native code and images" build step.
     */

    // jsCodeLocation = NSBundle.mainBundle().URLForResource("main", withExtension: "jsbundle")

    let rootView = RCTRootView(bundleURL:jsCodeLocation as URL!, moduleName: "PropertyFinder", initialProperties: nil, launchOptions:launchOptions)

    self.bridge = rootView?.bridge

    self.window = UIWindow(frame: UIScreen.main.bounds)
    let rootViewController = UIViewController()

    rootViewController.view = rootView

    self.window!.rootViewController = rootViewController;
    self.window!.makeKeyAndVisible()

    return true
  }
  1. 删除AppDelegate.hAppDelegate.m和主文件。

  2. 清理并构建您的项目。


我尝试了这个。RN 0.42; 应用程序编译和运行都没问题,但是 Xcode 项目从未找到 AppDelegate.swift 文件。模拟器显示黑屏。 - ajonno
我认为这些文件可能没有被添加到“项目”中。选择“Appdelegate文件”,并在“文件检查器”中检查您的项目名称是否已选中“目标成员资格”。如果文件甚至没有显示在Xcode中,那么您应该搜索“将文件添加到Xcode项目”。 - harsh_v
2
此答案已过时,请勿使用。 - MJ Studio

6

如果您在导入方面遇到问题

#import "RCTBridgeModule.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "RCTRootView.h"
#import "RCTUtils.h"
#import "RCTConvert.h"

尝试

#import <React/RCTBridgeModule.h>
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>

5
这对我实际有效:
import Foundation

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  var bridge: RCTBridge!

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let jsCodeLocation: URL

    jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index.ios", fallbackResource:nil)
    let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "REPLACE_WITH_YOUR_PROJECT_NAME", initialProperties: nil, launchOptions: launchOptions)
    let rootViewController = UIViewController()
    rootViewController.view = rootView

    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()

    return true
  }
}

注意:如果在使用@UIApplicationMain宏时遇到“创建多个应用程序”的错误,请尝试手动编写该宏的实现,方法请参考:https://dev59.com/GlkS5IYBdhLWcg3wV1Zy#50750540 - Jamie Birch

2
这是对我有效的方法:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate {
    func sourceURL(for bridge: RCTBridge!) -> URL! {
        #if DEBUG
            return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource:nil)
        #else
            return Bundle.main.url(forResource:"main", withExtension:"jsbundle")
        #endif
}

var window: UIWindow?
var bridge: RCTBridge!

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    self.bridge = RCTBridge(delegate: self, launchOptions: launchOptions)

    let rootView = RCTRootView(bridge: self.bridge, moduleName: "SolutoPartnersApp", initialProperties: nil)

    self.window = UIWindow(frame: UIScreen.main.bounds)
    let rootViewController = UIViewController()

    rootViewController.view = rootView

    self.window!.rootViewController = rootViewController;
    self.window!.makeKeyAndVisible()

    return true
}

func applicationWillResignActive(_ application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

func applicationDidEnterBackground(_ application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(_ application: UIApplication) {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

}


1

1)在Xcode中打开Workspace项目

2)删除以下文件:

  • AppDelegate.h
  • AppDelegate.m
  • main.m

3)创建一个名为AppDelegate的新的Swift文件,并在下一步中点击创建Bridging header。

4)将以下内容复制到AppDelegate.swift中:

import Foundation
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  var bridge: RCTBridge!

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let jsCodeLocation: URL

    jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index.ios", fallbackResource:nil)
    let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "REPLACE_WITH_YOUR_PROJECT_NAME", initialProperties: nil, launchOptions: launchOptions)
    let rootViewController = UIViewController()
    rootViewController.view = rootView

    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()

    return true
  }
}

5)将以下代码复制到桥接头文件中

#import "React/RCTBridgeModule.h"
#import "React/RCTBridge.h"
#import "React/RCTEventDispatcher.h"
#import "React/RCTRootView.h"
#import "React/RCTUtils.h"
#import "React/RCTConvert.h"
#import "React/RCTBundleURLProvider.h"

6) 现在运行您的项目


1
这在2021年有点起作用,但我不得不将 forBundleRoot: "index.ios" 更改为只是 "index"。另外,别忘了添加你的模块名称! - flunder

0

我研究了一下,发现react-native不支持该功能。

react-native init所做的是获取一个模板并更改其中的某些属性。

该模板是用Objective-C编写的,因此除了手动修改结果之外,您无法做任何事情。

但是,这并不应该真正影响您。即使在Objective-C项目中,您也可以使用Swift。无需将文件重写为Swift。


1
是的,最终我解决了问题。我的主要问题在于AppDelegate文件是用Obj-C编写的。所以,我用Swift版本替换了它们,然后它开始工作了。实际上,我缺少桥接头文件。 顺便感谢你的帮助 (y) - harsh_v

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接