You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JitsiMeetView.m 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * Copyright @ 2017-present Atlassian Pty Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <CoreText/CoreText.h>
  17. #import <React/RCTAssert.h>
  18. #import <React/RCTLinkingManager.h>
  19. #import <React/RCTRootView.h>
  20. #import "JitsiMeetView.h"
  21. #import "JitsiRCTBridgeWrapper.h"
  22. /**
  23. * A <tt>RCTFatalHandler</tt> implementation which swallows JavaScript errors.
  24. * In the Release configuration, React Native will (intentionally) raise an
  25. * unhandled NSException for an unhandled JavaScript error. This will
  26. * effectively kill the application. <tt>_RCTFatal</tt> is suitable to be in
  27. * accord with the Web i.e. not kill the application.
  28. */
  29. RCTFatalHandler _RCTFatal = ^(NSError *error)
  30. {
  31. id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
  32. @try {
  33. NSString *name
  34. = [NSString stringWithFormat:@"%@: %@",
  35. RCTFatalExceptionName, error.localizedDescription];
  36. NSString *message
  37. = RCTFormatError(error.localizedDescription, jsStackTrace, 75);
  38. [NSException raise:name format:@"%@", message];
  39. } @catch (NSException *e) {
  40. if (!jsStackTrace) {
  41. @throw;
  42. }
  43. }
  44. };
  45. @interface JitsiMeetView() {
  46. RCTRootView *rootView;
  47. }
  48. @end
  49. @implementation JitsiMeetView
  50. static JitsiRCTBridgeWrapper *jitsiBridge;
  51. #pragma mark linking delegate helpers
  52. // https://facebook.github.io/react-native/docs/linking.html
  53. + (BOOL)application:(UIApplication *)application
  54. continueUserActivity:(NSUserActivity *)userActivity
  55. restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler
  56. {
  57. return [RCTLinkingManager application:application
  58. continueUserActivity:userActivity
  59. restorationHandler:restorationHandler];
  60. }
  61. + (BOOL)application:(UIApplication *)application
  62. openURL:(NSURL *)url
  63. sourceApplication:(NSString *)sourceApplication
  64. annotation:(id)annotation
  65. {
  66. return [RCTLinkingManager application:application
  67. openURL:url
  68. sourceApplication:sourceApplication
  69. annotation:annotation];
  70. }
  71. #pragma mark initializers
  72. - (instancetype)initWithFrame:(CGRect)frame
  73. {
  74. self = [super initWithFrame:frame];
  75. if (self) {
  76. [self initialize];
  77. }
  78. return self;
  79. }
  80. - (instancetype)initWithCoder:(NSCoder *)aDecoder
  81. {
  82. self = [super initWithCoder:aDecoder];
  83. if (self) {
  84. [self initialize];
  85. }
  86. return self;
  87. }
  88. #pragma mark API
  89. /*
  90. * Loads the given URL and joins the specified conference. If the specified URL
  91. * is null, the welcome page is shown.
  92. */
  93. - (void)loadURL:(NSURL *)url
  94. {
  95. NSDictionary *props = url ? @{ url : url.absoluteString } : nil;
  96. if (rootView == nil) {
  97. rootView
  98. = [[RCTRootView alloc] initWithBridge:jitsiBridge.bridge
  99. moduleName:@"App"
  100. initialProperties:props];
  101. rootView.backgroundColor = self.backgroundColor;
  102. // Add React's root view as a subview which completely covers this one.
  103. [rootView setFrame:[self bounds]];
  104. [self addSubview:rootView];
  105. } else {
  106. // Update props with the new URL
  107. rootView.appProperties = props;
  108. }
  109. }
  110. #pragma mark private methods
  111. /*
  112. * Internal initialization:
  113. *
  114. * - sets the backgroudn color
  115. * - creates the React bridge
  116. * - loads the necessary custom fonts
  117. * - registers a custom fatal error error handler for React
  118. */
  119. - (void)initialize
  120. {
  121. static dispatch_once_t onceToken;
  122. dispatch_once(&onceToken, ^{
  123. // Set a background color which is in accord with the JavaScript and
  124. // Android parts of the application and causes less perceived visual
  125. // flicker than the default background color.
  126. self.backgroundColor
  127. = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
  128. // Initialize the React bridge.
  129. jitsiBridge = [[JitsiRCTBridgeWrapper alloc] init];
  130. // Dynamically load custom bundled fonts.
  131. [self loadCustomFonts];
  132. // Register a fatal error handler for React.
  133. [self registerFatalErrorHandler];
  134. });
  135. }
  136. /*
  137. * Helper function to dynamically load custom fonts. The UIAppFonts key in the
  138. * plist file doesn't work for frameworks, so fonts have to be manually loaded.
  139. */
  140. - (void)loadCustomFonts
  141. {
  142. NSBundle *bundle = [NSBundle bundleForClass:self.class];
  143. NSArray *fonts = [bundle objectForInfoDictionaryKey:@"JitsiKitFonts"];
  144. for (NSString *item in fonts) {
  145. NSString *fontName = [item stringByDeletingPathExtension];
  146. NSString *fontExt = [item pathExtension];
  147. NSString *fontPath = [bundle pathForResource:fontName ofType:fontExt];
  148. NSData *inData = [NSData dataWithContentsOfFile:fontPath];
  149. CFErrorRef error;
  150. CGDataProviderRef provider
  151. = CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
  152. CGFontRef font = CGFontCreateWithDataProvider(provider);
  153. if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
  154. CFStringRef errorDescription = CFErrorCopyDescription(error);
  155. NSLog(@"Failed to load font: %@", errorDescription);
  156. CFRelease(errorDescription);
  157. }
  158. CFRelease(font);
  159. CFRelease(provider);
  160. }
  161. }
  162. /*
  163. * Helper function to register a fatal error handler for React. Our handler
  164. * won't kill the process, it will swallow JS errors and print stack traces
  165. * instead.
  166. */
  167. - (void)registerFatalErrorHandler
  168. {
  169. #if !DEBUG
  170. // In the Release configuration, React Native will (intentionally) raise
  171. // an unhandled NSException for an unhandled JavaScript error. This will
  172. // effectively kill the application. In accord with the Web, do not kill
  173. // the application.
  174. if (!RCTGetFatalHandler()) {
  175. RCTSetFatalHandler(_RCTFatal);
  176. }
  177. #endif
  178. }
  179. @end