jiti-meet/ios/sdk/JitsiMeetView.m

213 lines
6.3 KiB
Mathematica
Raw Normal View History

/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <CoreText/CoreText.h>
#import <React/RCTAssert.h>
#import <React/RCTLinkingManager.h>
#import <React/RCTRootView.h>
#import "JitsiMeetView.h"
#import "JitsiRCTBridgeWrapper.h"
/**
* A <tt>RCTFatalHandler</tt> implementation which swallows JavaScript errors.
* In the Release configuration, React Native will (intentionally) raise an
* unhandled NSException for an unhandled JavaScript error. This will
* effectively kill the application. <tt>_RCTFatal</tt> is suitable to be in
* accord with the Web i.e. not kill the application.
*/
RCTFatalHandler _RCTFatal = ^(NSError *error)
{
id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
@try {
NSString *name
= [NSString stringWithFormat:@"%@: %@",
RCTFatalExceptionName, error.localizedDescription];
NSString *message
= RCTFormatError(error.localizedDescription, jsStackTrace, 75);
[NSException raise:name format:@"%@", message];
} @catch (NSException *e) {
if (!jsStackTrace) {
@throw;
}
}
};
@interface JitsiMeetView() {
RCTRootView *rootView;
}
@end
@implementation JitsiMeetView
static JitsiRCTBridgeWrapper *jitsiBridge;
#pragma mark linking delegate helpers
// https://facebook.github.io/react-native/docs/linking.html
+ (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
+ (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [RCTLinkingManager application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
#pragma mark initializers
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self initialize];
}
return self;
}
#pragma mark API
/*
* Loads the given URL and joins the specified conference. If the specified URL
* is null, the welcome page is shown.
*/
- (void)loadURL:(NSURL *)url
{
NSDictionary *props = url ? @{ url : url.absoluteString } : nil;
if (rootView == nil) {
rootView
= [[RCTRootView alloc] initWithBridge:jitsiBridge.bridge
moduleName:@"App"
initialProperties:props];
rootView.backgroundColor = self.backgroundColor;
// Add React's root view as a subview which completely covers this one.
[rootView setFrame:[self bounds]];
[self addSubview:rootView];
} else {
// Update props with the new URL
rootView.appProperties = props;
}
}
#pragma mark private methods
/*
* Internal initialization:
*
* - sets the backgroudn color
* - creates the React bridge
* - loads the necessary custom fonts
* - registers a custom fatal error error handler for React
*/
- (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Set a background color which is in accord with the JavaScript and
// Android parts of the application and causes less perceived visual
// flicker than the default background color.
self.backgroundColor
= [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
// Initialize the React bridge.
jitsiBridge = [[JitsiRCTBridgeWrapper alloc] init];
// Dynamically load custom bundled fonts.
[self loadCustomFonts];
// Register a fatal error handler for React.
[self registerFatalErrorHandler];
});
}
/*
* Helper function to dynamically load custom fonts. The UIAppFonts key in the
* plist file doesn't work for frameworks, so fonts have to be manually loaded.
*/
- (void)loadCustomFonts
{
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSArray *fonts = [bundle objectForInfoDictionaryKey:@"JitsiKitFonts"];
for (NSString *item in fonts) {
NSString *fontName = [item stringByDeletingPathExtension];
NSString *fontExt = [item pathExtension];
NSString *fontPath = [bundle pathForResource:fontName ofType:fontExt];
NSData *inData = [NSData dataWithContentsOfFile:fontPath];
CFErrorRef error;
CGDataProviderRef provider
= CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error);
NSLog(@"Failed to load font: %@", errorDescription);
CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);
}
}
/*
* Helper function to register a fatal error handler for React. Our handler
* won't kill the process, it will swallow JS errors and print stack traces
* instead.
*/
- (void)registerFatalErrorHandler
{
#if !DEBUG
// In the Release configuration, React Native will (intentionally) raise
// an unhandled NSException for an unhandled JavaScript error. This will
// effectively kill the application. In accord with the Web, do not kill
// the application.
if (!RCTGetFatalHandler()) {
RCTSetFatalHandler(_RCTFatal);
}
#endif
}
@end