Running react-native app on iOS device using offline bundle

tl;dr Make sure your localhost ip address is explicitly stated in your hosts file, and that your hosts file hasn't become corrupted.

So our team kept hitting this issue. It turns out that React Native reads the host file on your machine looking for the URL to store, so that it can pull the js to create an offline bundle, or to just reach the packager while the app is running on your device.

We actually weren't trying to run this as an offline bundle, just in the ios simulator, so we were left really scratching our heads. We found the fix because the needed fix was also causing other issues with react native. Our etc/hosts file on a mac didn't have the localhost ip explicitly stated. I added that in and the problem seemed to go away. Forgive me as I don't know much about osx and dns resolution but it seems that with the new automatic ip detection, this is now necessary.

I am not sure how react native is getting the ip, if it is reading the hosts file, or the host file is propogating something else in osx that rn is reading, but if the above fix doesnt work for you, I would look to see if the hosts file itself is corrupted with certain characters that cause it not to be read. In my hunting for the solution to this problem, I came across many posts and questions about malformed hosts files that caused issues with localhost being resolved properly.

Also, it seems there is an effort underway to update the ip detection, but I am not well versed enough in obj c to know if this issue would be corrected by the new code. Maybe someone can take a look? https://github.com/facebook/react-native/pull/8789

Another also, clearing your osx DNS cache may help https://coolestguidesontheplanet.com/clear-the-local-dns-cache-in-osx/


EDIT: The whole bundle ip detection should be automatic on the latest release of react-native. If you select your device on xcode do build and run and run the app once. It should save an offline bundle on the phone so that if it doesn't find a packager server running, it will use the offline bundle.

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


If you change to a release scheme while building your app, that will compile your app with the offline bundle.

Product > Scheme > Edit Scheme > set build configuration to Release.

Not sure why they didn't update the documentation for the Appdelegate.m method. Looks like the line is still there on the sources. [Edit: there's a pull request for this]


For me the problem was that I had fiddled with the Info.plist and removed the localhost app transport security exception. Adding this back into Info.plist fixed it for me:

<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>

When I open the global proxy in ShadowsocksX, automatic IP detection won't return http://localhost:8081/index.ios.bundle in the debug mode. That's why the URL for main.jsbundle returned as null.

How to solve?

Option 1:

replace

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

with

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

This method could disable automatic IP detection.

Option 2:

Switch your proxy mode if you open the global proxy mode.

Tags:

React Native