使用离线 bundle 在 iOS 设备上运行 react-native 应用程序

17
"The official React Native documentation on running an app on an iOS device using an offline bundle states that:
Open ios/YourApp/AppDelegate.m Uncomment the line, jsCodeLocation = [[NSBundle mainBundle] ...
However, with the latest version of react-native 0.30.0, this line is no longer present in the default AppDelegate.m file. Here is an excerpt from the default AppDelegate.m file."
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                    moduleName:@"TestAppDelete"
                                             initialProperties:nil
                                                 launchOptions:launchOptions];

如果我尝试像以前的版本那样使用jsCodeLocation,它将返回null。
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

我不确定为什么main.jsbundle的URL返回为null。它是否不再由打包器创建。如果应该使用最新版本创建,如何确认?
如果您已经在iOS设备上使用离线捆绑运行了react-native 0.30.0应用程序,请分享如何操作的说明。
6个回答

28

编辑:在最新的react-native版本中,整个IP检测捆绑应该是自动的。如果您在Xcode上选择了您的设备并进行 build and run 操作,并运行一次应用程序,它将在手机上保存一个离线捆绑包,以便在找不到打包器服务器运行时,将使用离线捆绑包。

来源:https://github.com/facebook/react-native/commit/8c29a52c54392ce52148e7d3aa9f835537453aa4


如果您在构建应用程序时切换到 release 方案,则会使用离线捆绑包来编译您的应用程序。

Product > Scheme > Edit Scheme > 将 build configuration 设置为 Release

不确定为什么他们没有更新 Appdelegate.m 方法的文档。看起来该行仍然在源代码中。[编辑:对此有一个拉取请求]


1
非常感谢您的回复。这个更改在发布说明中并没有提到,由于我改变了我的应用程序中的AppDelegate文件,在react-native升级后我只是替换它,而且文档也没有更新,这使情况更加混乱。请注意 - 如果我在没有将“Build Configuration”更改为“Release”的情况下在设备上运行应用程序,只要它连接到Mac,我就能够运行该应用程序。如果我停止应用程序,断开电话并尝试再次运行它,则无法启动。在这种情况下,设置“Build Configuration”为“Release”有助于解决问题。再次感谢! - Varun Gupta
谢谢,老兄!如果不是你的回答,我就不会知道了。 :) 我还没有尝试过,但在源代码中看到了它。一旦我尝试过,我会更新的。 - nabn
3
一旦切换到发布版本,我就无法再使用React Native调试器来调试我的应用程序。此外,构建时间非常长。这是唯一的解决方案吗?我能否以某种方式解决这个问题并保持在调试模式下运行?谢谢。 - Uri Klar
1
切换到发布配置只解决了一半的问题。发布构建不允许调试,这使我们有点摸不着头脑。 - Eric G
1
@EdoftheMountain 我们在不改变发布版本的情况下修复了它,请查看我们在这里所做的 https://dev59.com/s1kT5IYBdhLWcg3wT91f#40730709 - Fralcon
显示剩余2条评论

13

当我在ShadowsocksX中打开全局代理时,在调试模式下,自动IP检测不会返回http://localhost:8081/index.ios.bundle,这就是为什么main.jsbundle的URL返回null

如何解决?

选项1:

替换

jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

随着

jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];

此方法可以禁用自动IP检测。

选项2:

如果您打开了全局代理模式,请切换代理模式。


最新的react-native版本已经不再支持选项1。 - dcp

3
确保您的本地主机IP地址明确地在您的hosts文件中声明,并且您的hosts文件没有损坏。我们的团队一直遇到这个问题。原来,React Native读取您机器上的主机文件,寻找要存储的URL,以便可以拉取js创建离线包,或者只是在应用程序在您的设备上运行时访问打包器。我们实际上并没有尝试将其作为离线包运行,只是在ios模拟器中运行,所以我们感到非常困惑。我们找到了解决方法,因为所需的修复还会导致React Native的其他问题。我们的mac上的etc/hosts文件没有明确声明本地主机IP。我添加了它,问题似乎消失了。请原谅我对osx和dns解析不太了解,但似乎随着新的自动IP检测,现在有必要这样做。
我不确定React Native是如何获取IP地址的,它是否读取主机文件,或者主机文件正在传播OSX中的其他内容,而rn正在读取,但如果上述修复方法对您无效,我会查看主机文件本身是否被某些字符破坏,导致无法正确读取。在寻找解决此问题的解决方案时,我遇到了许多关于格式不正确的主机文件的帖子和问题,这些文件会导致本地主机无法正确解析。

此外,似乎正在进行更新IP检测的努力,但我不太精通obj c,不知道新代码是否会纠正此问题。也许有人可以看一下?https://github.com/facebook/react-native/pull/8789

另外,清除OSX DNS缓存可能会有所帮助https://coolestguidesontheplanet.com/clear-the-local-dns-cache-in-osx/


1
+1 .. 太棒了的研究!我只在某些路由器上遇到了这个问题。(我经常移动)。但是指向主机的行已被注释掉。将 127.0.0.1 localhost 放入我的hosts文件中解决了这个问题!非常感谢你!我为解决这个问题搜索了几个小时。 - Tex0gen

2

对我来说,问题在于我修改了Info.plist并删除了本地主机应用程序传输安全例外。将其添加回Info.plist后,问题得到解决:

<key>NSAppTransportSecurity</key>
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

2

我在react native 0.37上唯一能行的方法是回到“老派”的方式,在AppDelegate.m中手动编辑jsCodeLocation。现在调试又好使了!

确保您的设备和开发机器连接到同一个 Wi-Fi,并在让它工作之前可能要断开任何有线以太网。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSURL *jsCodeLocation;

  // Comment-out, cannot get past error: bundleURL must be non-nil when not implementing loadSourceForBridge
  //jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

#if DEBUG
  NSLog(@"AppDelegate:DEBUG");

#if TARGET_IPHONE_SIMULATOR
  NSLog(@"AppDelegate:DEBUG:TARGET_IPHONE_SIMULATOR");
  jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];
#else
  NSLog(@"AppDelegate:DEBUG:!TARGET_IPHONE_SIMULATOR");
  NSLog(@"To device debug, open RCTWebSocketExecutor.m & replace localhost with MacBook IP.");
  // Get dev host IP Address:
  //    ifconfig | grep inet\ | tail -1 | cut -d " " -f 2
  jsCodeLocation = [NSURL URLWithString:@"http://192.16.29.213:8081/index.ios.bundle"];
#endif

#else
  NSLog(@"AppDelegate:RELEASE jsbundle");
  jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif

  NSLog(@"jsCodeLocation = %@",jsCodeLocation);


  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"BluetoothConnect"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];
  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}

0

首先,我会确保已经安装了ios-deploy

您可以通过运行npm install -g ios-deploy来安装它。

然后将您想要安装应用程序的iPhone连接到您的Mac上。

接着运行

react-native run-ios --device "ABC’s iPhone" --configuration=release

这将创建一个离线的JS捆绑应用程序并将其安装到iPhone上。
PS:如果它报错说
Signing for "<app name>" requires a development team. 
Select a development team in the project editor.

然后在 Xcode 中打开 ios/ 内的项目,选择目标 -> 通用选项卡,在签名下选择签名团队并选择自动管理签名。

然后保存并重新运行命令。


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