Skip to content

Standalone in iOS not loading up JS template code. #199

Open
@EliG-TA

Description

Hey! I cannot understand why I am having so much difficulty getting this library setup for IOS. I got it working with minimal effort on my part for Android. This issue is happening after I followed meticulously what the documentations say on setting up for IOS, but to no avail. What could I possibly be doing wrong. FYI, I'm trying very hard to use this library with my Expo project even though this is a bare bones React Native library and it was not built for this use case. However, I feel like I am getting very close. I am fully aware that this library has been transitioning from Objective-C in favor of Swift for much of the code base, however I since I am trying to keep my App stable being that it uses a lot of Expo, I would like to keep it in Objective-C if possible.

Here is the error output:

⚠️ ld: Could not find or use auto-linked framework 'CoreAudioTypes': framework 'CoreAudioTypes' not found
❌ clang: error: linker command failed with exit code 1 (use -v to see invocation)

Here is my relevant project folder layout and code:

.
└── ./ios/
├── ./ios/build/
├── ./ios/Pods/
├── ./ios/MyProject/
│ ├── ./ios/MyProject/Images.xcassets/
│ ├── ./ios/MyProject/Supporting/
│ ├── ./ios/MyProject/AppDelegate.h
│ ├── ./ios/MyProject/AppDelegate.mm
│ ├── ./ios/MyProject/CarSceneDelegate.h
│ ├── ./ios/MyProject/CarSceneDelegate.m
│ ├── ./ios/MyProject/Info.plist
│ ├── ./ios/MyProject/main.m
│ ├── ./ios/MyProject/noop-file.swift
│ ├── ./ios/MyProject/PhoneSceneDelegate.h
│ ├── ./ios/MyProject/PhoneSceneDelegate.m
│ ├── ./ios/MyProject/SplashScreen.storyboard
│ ├── ./ios/MyProject/MyProject-Bridging-Header.h
│ └── ./ios/MyProject/MyProject.entitlements
├── ./ios/MyProject.xcodeproj/
├── ./ios/MyProject.xcworkspace/
└── ./ios/Other Files

AppDelegate.h

#import <Foundation/Foundation.h>
#import <React/RCTBridgeDelegate.h>
#import <RCTAppDelegate.h>
#import <UIKit/UIKit.h>
#import <Expo/Expo.h>
#import <CarPlay/CarPlay.h>

@interface AppDelegate : EXAppDelegateWrapper <RCTBridgeDelegate, UIApplicationDelegate, CPApplicationDelegate>

@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) UIView *rootView;
@property (nonatomic, strong) RCTBridge *bridge;

- (void)initAppFromSceneWithConnectionOptions:(UISceneConnectionOptions *)connectionOptions;

@end

AppDelegate.mm

#import <RNCarPlay.h>
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>
#import <Firebase/Firebase.h>

#import "CarSceneDelegate.h"
#import "PhoneSceneDelegate.h"

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTLinkingManager.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// @generated begin @react-native-firebase/app-didFinishLaunchingWithOptions - expo prebuild (DO NOT MODIFY) sync-ecd111c37e49fdd1ed6354203cd6b1e2a38cccda
[FIRApp configure];
// @generated end @react-native-firebase/app-didFinishLaunchingWithOptions
  self.moduleName = @"main";

  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  return [self getBundleURL];
}

- (NSURL *)getBundleURL
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}

// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
  BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
  return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
}

// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
  return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
  return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
}

// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
  return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}


- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
    if (@available(iOS 13.0, *)) {
        if (connectingSceneSession.role == CPTemplateApplicationSceneSessionRoleApplication) {
            UISceneConfiguration *scene = [[UISceneConfiguration alloc] initWithName:@"CarPlay" sessionRole:connectingSceneSession.role];
            scene.delegateClass = [CarSceneDelegate class];
            return scene;
        } else {
            UISceneConfiguration *scene = [[UISceneConfiguration alloc] initWithName:@"Phone" sessionRole:connectingSceneSession.role];
            scene.delegateClass = [PhoneSceneDelegate class];
            return scene;
        }
    } else {
        return nil;
    }
}

- (UIView *)rootView {
    if (!_rootView) {
        if (!self.bridge) {
            self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
        }
        _rootView = [[RCTRootView alloc] initWithBridge:self.bridge
                                             moduleName:@"main"
                                      initialProperties:nil];
    }
    return _rootView;
}

- (void)initAppFromSceneWithConnectionOptions:(UISceneConnectionOptions *)connectionOptions
{
    if (!self.bridge) {
        self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:[self connectionOptionsToLaunchOptions:connectionOptions]];
    }
    self.rootView = [self rootView];
}

- (NSDictionary *)connectionOptionsToLaunchOptions:(UISceneConnectionOptions *)connectionOptions
{
    NSMutableDictionary *launchOptions = [NSMutableDictionary dictionary];

    if (connectionOptions.notificationResponse) {
        launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] = connectionOptions.notificationResponse.notification.request.content.userInfo;
    }

    if (connectionOptions.userActivities.count > 0) {
        NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject;
        NSDictionary *userActivityDictionary = @{
            @"UIApplicationLaunchOptionsUserActivityTypeKey": userActivity.activityType,
            @"UIApplicationLaunchOptionsUserActivityKey": userActivity
        };
        launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey] = userActivityDictionary;
    }

    return launchOptions;
}

- (void)application:(UIApplication *)application didConnectCarInterfaceController:(CPInterfaceController *)interfaceController toWindow:(CPWindow *)window {
  [RNCarPlay connectWithInterfaceController:interfaceController window:window];
}

- (void)application:(nonnull UIApplication *)application didDisconnectCarInterfaceController:(nonnull CPInterfaceController *)interfaceController fromWindow:(nonnull CPWindow *)window {
  [RNCarPlay disconnect];
}

@end

CarSceneDelegate.h

#import <UIKit/UIKit.h>
#import <CarPlay/CarPlay.h>

@interface CarSceneDelegate : UIResponder <CPTemplateApplicationSceneDelegate>

@end

CarSceneDelegate

#import "CarSceneDelegate.h"
#import "AppDelegate.h"
#import <RNCarPlay.h>

@implementation CarSceneDelegate

- (void)templateApplicationScene:(CPTemplateApplicationScene *)templateApplicationScene
       didConnectInterfaceController:(CPInterfaceController *)interfaceController {
    AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate;
    [appDelegate initAppFromSceneWithConnectionOptions:templateApplicationScene.connectionOptions];
    [RNCarPlay connectWithInterfaceController:interfaceController window:templateApplicationScene.carWindow];
}

- (void)templateApplicationScene:(CPTemplateApplicationScene *)templateApplicationScene
       didDisconnectInterfaceController:(CPInterfaceController *)interfaceController {
    [RNCarPlay disconnect];
}

@end

main.m

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

PhoneSceneDelegate.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface PhoneSceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

PhoneSceneDelegate.m

#import "PhoneSceneDelegate.h"
#import "AppDelegate.h"

@implementation PhoneSceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate;
    UIWindowScene *windowScene = (UIWindowScene *)scene;
    
    [appDelegate initAppFromSceneWithConnectionOptions:connectionOptions];
    
    UIViewController *rootViewController = [[UIViewController alloc] init];
    rootViewController.view = appDelegate.rootView;
    UIWindow *window = [[UIWindow alloc] initWithWindowScene:windowScene];
    window.rootViewController = rootViewController;
    self.window = window;
    [window makeKeyAndVisible];
}

@end

To Reproduce
Try building the project with my configuration for IOS.

Expected behavior
To build successfully for IOS.

Screenshots/Videos
If applicable, add screenshots to help explain your problem.

CarPlay (please complete the following information):

  • Device: iPhone 13 mini simulator
  • OS version IOS 15.5
  • RNCarPlay version 2.4.0-beta.2

Additional context
I have the following Apple entitlements:
"com.apple.developer.carplay-audio": true,
"com.apple.developer.playable-content": true

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions