Closed dawidzawada closed 2 years ago
Hi @dawidzawada!
Is this method (- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
) implemented in your App Clip's AppDelegate
?
If it is not implemented, then React Native doesn't know the location of the JS Bundle.
I've added the - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
method as well as:
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
....
code in didFinishLaunchingWithOptions
I can see the Decompression Time log in Xcode console but the same error still occurs, I'm not experienced in React Native configuration but I'm suspecting that is related to my ViewController - app is builded successfully but error occurs at runtime - i can see just white background. Here's my ViewController code:
#import "ViewController.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
@implementation ViewController
- (void)loadView {
#if DEBUG
// When debugging we load the js bundle from the Metro Bundler
// running on your development machine. "index" is the name of the
// js file used as an entry point (don't include the extension).
NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings]
jsBundleURLForBundleRoot:@"index.clip" fallbackResource:nil];
#else
// For release builds we add the js bundle to the build.
// By default the js bundler will create a file called
// "main.jsbundle" for us.
NSURL *jsCodeLocation = [[NSBundle mainBundle]
URLForResource:@"main" withExtension:@"jsbundle"];
#endif
// moduleName corresponds to the appName used for the
// app entry point in "index.js"
RCTRootView *rootView = [[RCTRootView alloc]
initWithBundleURL:jsCodeLocation moduleName:@“<NAME OF THE APP>”
initialProperties:nil launchOptions:nil];
// Default to a white background.
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f
green:1.0f blue:1.0f alpha:1];
self.view = rootView;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
@end
And my AppClip's AppDelegate:
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <react-native-compressed-jsbundle/IMOCompressedBundleLoader.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@“<NAME OF THE APP>”
initialProperties:nil];
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
- (void)loadSourceForBridge:(RCTBridge *)bridge onProgress:(RCTSourceLoadProgressBlock)onProgress onComplete:(RCTSourceLoadBlock)loadCallback {
[IMOCompressedBundleLoader loadSourceForBridge:bridge bridgeDelegate:self onProgress:onProgress onComplete:loadCallback];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
I'm guessing that loadView
from ViewController might cause some troubles with - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
. Is that the issue?
Looking at the code, I don't see your custom ViewController
class being used anywhere at all. So it is unlikely that it can cause any problems.
If your Main App works, and the App Clip doesn't, you can try to look for differences between the two. It is clearly some kind of misconfiguration of the Clip.
You can post your main app's App Delegate here, so we can look together.
I've found the issue, both AppDelegate were almost identical but I've noticed some differences between Info.plist files - mine Clip version has these tags:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
And full app does not - I've removed them from the app clip and app seems to be working and size reduced to exact 10MB after some additional other code clean-up, still some work ahead but this package helped a lot! Thanks for your work and support!
Glad the issue is resolved! Feel free to contact me if the lib misbehaves somehow.
By the way, can you please send me the Decompression Time log lines from your console? I'm trying to find out how the compression algorithm works on real-world examples.
And also, stay tuned for the updates — I've found that using Apple's Compression framework improves the metrics, and I might provide it as an additional option instead of Brotli.
Sure, here's my compression logs: App Clip:
[react-native-compressed-jsbundle] Decompression time overhead: 0.0186236 s
Original size: 2684.33 KB
Compressed size: 449.661 KB
Full App:
[react-native-compressed-jsbundle] Decompression time overhead: 0.0186168 s
Original size: 3140.17 KB
Compressed size: 525.125 KB
In my opinion these are pretty good results - especially for AppClip - after adding stripe-react-native package AppClip size was around 12/13 MB, now, after compression and removing a few pods it's 10.3 MB - that lead me closer to achieving planned functionalities. So this is definitely useful package for React Native AppClips. Out of curiosity, how much do you expect compression to gain by using Apple's Compression?
@dawidzawada @ivanmoskalev I'm running exactly on the same issue but I can't remove the code you mentioned from Info.plist file because I'm using SceneDelegate for URL handling, any advices?
@dawidzawada @ivanmoskalev I'm running exactly on the same issue but I can't remove the code you mentioned from Info.plist file because I'm using SceneDelegate for URL handling, any advices?
Not really, I've removed SceneDelegate to test how much i can gain with the compression but I'm also using it for URL handling, issue should be reopened. @ivanmoskalev
I don't see how this is an issue of this library. Please upload a minimal reproducible example
@ivanmoskalev Here is a minimal reproducible example: https://github.com/zeabdelkhalek/react-native-compressed-jsbundle-appclip-example To reproduce the issue just clone the repository, npm & pod install, run the app clip in debug mode, it will work fine, switch to release and it will crash with the error mentioned in this issue, if you remove the compress script from the build phase it will also work fine.
I resolved my issue by removing completely SceneDelegate and ViewController files and moved all the logic to AppDelegate, I also created a module for passing URL from AppDelegate to react-native side
Hi, thanks for the example. Will investigate and try to fix the lib tonight.
Hi, I was able to run compression library for the full App but the App Clip version(Release mode) app build successfully but crashes after a second and Xcode points to an error:
com.facebook.react.JavaScript (10): "Could not get BatchedBridge, make sure your bundle is packaged correctly"
Also Clip's
AppDelegate.m
file shows warning at self keyword:My build phase config for RN Code & Images looks like this:
And of course Im importing library in full app and clip AppDelegates:
#import <react-native-compressed-jsbundle/IMOCompressedBundleLoader.h>
Also Xcode logs some errors in console:
What might be the issue of the AppClip? Full app is working perfectly and library reduces size of jsbundle.