rn: add ability to disable crash reporting

This commit is contained in:
tmoldovan8x8 2020-05-08 00:05:48 +03:00 committed by GitHub
parent f646bc7a7a
commit b3f16926d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 267 additions and 62 deletions

View File

@ -1,8 +1,5 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
boolean googleServicesEnabled \
= project.file('google-services.json').exists() && !rootProject.ext.libreBuild
// Crashlytics integration is done as part of Firebase now, so it gets // Crashlytics integration is done as part of Firebase now, so it gets
// automagically activated with google-services.json // automagically activated with google-services.json
if (googleServicesEnabled) { if (googleServicesEnabled) {
@ -13,7 +10,7 @@ if (googleServicesEnabled) {
// This lets us upload a new build at most every 10 seconds for the // This lets us upload a new build at most every 10 seconds for the
// next ~680 years. // next ~680 years.
// https://stackoverflow.com/a/38643838 // https://stackoverflow.com/a/38643838
def vcode = (int)(((new Date().getTime()/1000) - 1546297200) / 10) def vcode = (int) (((new Date().getTime() / 1000) - 1546297200) / 10)
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
@ -143,8 +140,8 @@ gradle.projectsEvaluated {
def targetName = variant.name.capitalize() def targetName = variant.name.capitalize()
def currentRunPackagerTask = tasks.create( def currentRunPackagerTask = tasks.create(
name: "run${targetName}ReactPackager", name: "run${targetName}ReactPackager",
type: Exec) { type: Exec) {
group = "react" group = "react"
description = "Run the React packager." description = "Run the React packager."
@ -175,5 +172,5 @@ gradle.projectsEvaluated {
} }
if (googleServicesEnabled) { if (googleServicesEnabled) {
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
} }

View File

@ -7,6 +7,7 @@ import com.crashlytics.android.Crashlytics;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks; import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import io.fabric.sdk.android.Fabric; import io.fabric.sdk.android.Fabric;
import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity; import org.jitsi.meet.sdk.JitsiMeetActivity;
/** /**
@ -21,7 +22,9 @@ final class GoogleServicesHelper {
if (BuildConfig.GOOGLE_SERVICES_ENABLED) { if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services"); Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
Fabric.with(activity, new Crashlytics()); if (!JitsiMeet.isCrashReportingDisabled(activity)) {
Fabric.with(activity, new Crashlytics());
}
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent()) FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
.addOnSuccessListener(activity, pendingDynamicLinkData -> { .addOnSuccessListener(activity, pendingDynamicLinkData -> {

View File

@ -161,6 +161,8 @@ ext {
// Libre build // Libre build
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean() libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
} }
// Force the version of the Android build tools we have chosen on all // Force the version of the Android build tools we have chosen on all

View File

@ -14,11 +14,13 @@ android {
buildTypes { buildTypes {
debug { debug {
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}" buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${rootProject.ext.googleServicesEnabled}"
} }
release { release {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}" buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${rootProject.ext.googleServicesEnabled}"
} }
} }
@ -70,6 +72,7 @@ dependencies {
implementation project(':react-native-calendar-events') implementation project(':react-native-calendar-events')
implementation project(':react-native-community-async-storage') implementation project(':react-native-community-async-storage')
implementation project(':react-native-community_netinfo') implementation project(':react-native-community_netinfo')
implementation project(':react-native-default-preference')
implementation project(':react-native-immersive') implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake') implementation project(':react-native-keep-awake')
implementation project(':react-native-linear-gradient') implementation project(':react-native-linear-gradient')

View File

@ -76,6 +76,7 @@ class AppInfoModule
"version", "version",
packageInfo == null ? "" : packageInfo.versionName); packageInfo == null ? "" : packageInfo.versionName);
constants.put("LIBRE_BUILD", BuildConfig.LIBRE_BUILD); constants.put("LIBRE_BUILD", BuildConfig.LIBRE_BUILD);
constants.put("GOOGLE_SERVICES_ENABLED", BuildConfig.GOOGLE_SERVICES_ENABLED);
return constants; return constants;
} }

View File

@ -16,11 +16,14 @@
*/ */
package org.jitsi.meet.sdk; package org.jitsi.meet.sdk;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManager;
public class JitsiMeet { public class JitsiMeet {
/** /**
* Default {@link JitsiMeetConferenceOptions} which will be used for all conferences. When * Default {@link JitsiMeetConferenceOptions} which will be used for all conferences. When
* joining a conference these options will be merged with the ones passed to * joining a conference these options will be merged with the ones passed to
@ -72,4 +75,10 @@ public class JitsiMeet {
reactInstanceManager.showDevOptionsDialog(); reactInstanceManager.showDevOptionsDialog();
} }
} }
public static boolean isCrashReportingDisabled(Context context) {
SharedPreferences preferences = context.getSharedPreferences("jitsi-default-preferences", Context.MODE_PRIVATE);
String value = preferences.getString("isCrashReportingDisabled", "");
return Boolean.parseBoolean(value);
}
} }

View File

@ -190,6 +190,7 @@ class ReactInstanceManagerHolder {
new com.corbt.keepawake.KCKeepAwakePackage(), new com.corbt.keepawake.KCKeepAwakePackage(),
new com.facebook.react.shell.MainReactPackage(), new com.facebook.react.shell.MainReactPackage(),
new com.horcrux.svg.SvgPackage(), new com.horcrux.svg.SvgPackage(),
new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
new com.ocetnik.timer.BackgroundTimerPackage(), new com.ocetnik.timer.BackgroundTimerPackage(),
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(), new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
new com.reactnativecommunity.netinfo.NetInfoPackage(), new com.reactnativecommunity.netinfo.NetInfoPackage(),

View File

@ -9,6 +9,8 @@ include ':react-native-community-async-storage'
project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android') project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android')
include ':react-native-community_netinfo' include ':react-native-community_netinfo'
project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android') project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android')
include ':react-native-default-preference'
project(':react-native-default-preference').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-default-preference/android')
include ':react-native-google-signin' include ':react-native-google-signin'
project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android') project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android')
include ':react-native-immersive' include ':react-native-immersive'

View File

@ -66,6 +66,7 @@ target 'JitsiMeet' do
pod 'RNSound', :path => '../node_modules/react-native-sound' pod 'RNSound', :path => '../node_modules/react-native-sound'
pod 'RNSVG', :path => '../node_modules/react-native-svg' pod 'RNSVG', :path => '../node_modules/react-native-svg'
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity' pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
# Native pod dependencies # Native pod dependencies
# #

View File

@ -353,6 +353,8 @@ PODS:
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1) - ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
- RNCAsyncStorage (1.3.4): - RNCAsyncStorage (1.3.4):
- React - React
- RNDefaultPreference (1.4.2):
- React
- RNGoogleSignin (3.0.1): - RNGoogleSignin (3.0.1):
- GoogleSignIn (~> 5.0.0) - GoogleSignIn (~> 5.0.0)
- React - React
@ -409,6 +411,7 @@ DEPENDENCIES:
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`) - ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)" - "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
- "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)" - "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)"
- RNSound (from `../node_modules/react-native-sound`) - RNSound (from `../node_modules/react-native-sound`)
- RNSVG (from `../node_modules/react-native-svg`) - RNSVG (from `../node_modules/react-native-svg`)
@ -416,13 +419,11 @@ DEPENDENCIES:
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS: SPEC REPOS:
https://github.com/CocoaPods/Specs.git: trunk:
- Amplitude-iOS - Amplitude-iOS
- AppAuth
- boost-for-react-native - boost-for-react-native
- CocoaLumberjack - CocoaLumberjack
- ObjectiveDropboxOfficial
trunk:
- AppAuth
- Crashlytics - Crashlytics
- Fabric - Fabric
- Firebase - Firebase
@ -442,6 +443,7 @@ SPEC REPOS:
- GTMAppAuth - GTMAppAuth
- GTMSessionFetcher - GTMSessionFetcher
- nanopb - nanopb
- ObjectiveDropboxOfficial
- PromisesObjC - PromisesObjC
EXTERNAL SOURCES: EXTERNAL SOURCES:
@ -509,6 +511,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon" :path: "../node_modules/react-native/ReactCommon"
RNCAsyncStorage: RNCAsyncStorage:
:path: "../node_modules/@react-native-community/async-storage" :path: "../node_modules/@react-native-community/async-storage"
RNDefaultPreference:
:path: "../node_modules/react-native-default-preference"
RNGoogleSignin: RNGoogleSignin:
:path: "../node_modules/@react-native-community/google-signin" :path: "../node_modules/@react-native-community/google-signin"
RNSound: RNSound:
@ -578,12 +582,13 @@ SPEC CHECKSUMS:
React-RCTVibration: a1bcfcdc0b5a73a1b0829a34cee22bd0e95bacba React-RCTVibration: a1bcfcdc0b5a73a1b0829a34cee22bd0e95bacba
ReactCommon: 675681aba4fecff5acbc0e440530cc422103c610 ReactCommon: 675681aba4fecff5acbc0e440530cc422103c610
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323 RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20 RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
RNSVG: aac12785382e8fd4f28d072fe640612e34914631 RNSVG: aac12785382e8fd4f28d072fe640612e34914631
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42 RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f
PODFILE CHECKSUM: f615794fb9184757b00cd16e534824ba6ee2fc98 PODFILE CHECKSUM: 082858daebbe170e7a490de433e7f2a99e0c3701
COCOAPODS: 1.9.1 COCOAPODS: 1.9.1

View File

@ -24,19 +24,10 @@
@import Firebase; @import Firebase;
@import JitsiMeet; @import JitsiMeet;
@implementation AppDelegate @implementation AppDelegate
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
NSLog(@"Enablign Crashlytics and Firebase");
[FIRApp configure];
[Fabric with:@[[Crashlytics class]]];
}
JitsiMeet *jitsiMeet = [JitsiMeet sharedInstance]; JitsiMeet *jitsiMeet = [JitsiMeet sharedInstance];
jitsiMeet.conferenceActivityType = JitsiMeetConferenceActivityType; jitsiMeet.conferenceActivityType = JitsiMeetConferenceActivityType;
@ -54,6 +45,13 @@
#endif #endif
}]; }];
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
if ([FIRUtilities appContainsRealServiceInfoPlist] && ![jitsiMeet isCrashReportingDisabled]) {
NSLog(@"Enabling Crashlytics and Firebase");
[FIRApp configure];
[Fabric with:@[[Crashlytics class]]];
}
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions]; [jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
return YES; return YES;

View File

@ -16,12 +16,7 @@
#import "FIRUtilities.h" #import "FIRUtilities.h"
// Plist file name. @import JitsiMeet;
NSString *const kGoogleServiceInfoFileName = @"GoogleService-Info";
// Plist file type.
NSString *const kGoogleServiceInfoFileType = @"plist";
NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
@implementation FIRUtilities @implementation FIRUtilities
@ -30,37 +25,11 @@ NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
NSBundle *bundle = [NSBundle mainBundle]; NSBundle *bundle = [NSBundle mainBundle];
containsRealServiceInfoPlist = [self containsRealServiceInfoPlistInBundle:bundle]; containsRealServiceInfoPlist = [InfoPlistUtil containsRealServiceInfoPlistInBundle:bundle];
}); });
return containsRealServiceInfoPlist; return containsRealServiceInfoPlist;
} }
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle {
NSString *bundlePath = bundle.bundlePath;
if (!bundlePath.length) {
return NO;
}
NSString *plistFilePath = [bundle pathForResource:kGoogleServiceInfoFileName
ofType:kGoogleServiceInfoFileType];
if (!plistFilePath.length) {
return NO;
}
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
if (!plist) {
return NO;
}
// Perform a very naive validation by checking to see if the plist has the dummy google app id
NSString *googleAppID = plist[kGoogleAppIDPlistKey];
if (!googleAppID.length) {
return NO;
}
return YES;
}
+ (NSURL *)extractURL: (FIRDynamicLink*)dynamicLink { + (NSURL *)extractURL: (FIRDynamicLink*)dynamicLink {
NSURL *url = nil; NSURL *url = nil;
if (dynamicLink != nil) { if (dynamicLink != nil) {

View File

@ -42,6 +42,8 @@
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; }; C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; };
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; }; C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; }; C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
C8AFD27F2462C613000293D2 /* InfoPlistUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
C8AFD2802462C613000293D2 /* InfoPlistUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */; };
DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; }; DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; };
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; }; DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; };
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; }; DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; };
@ -105,6 +107,8 @@
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; }; C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; }; C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; }; C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InfoPlistUtil.h; sourceTree = "<group>"; };
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InfoPlistUtil.m; sourceTree = "<group>"; };
DE438CD82350934700DD541D /* JavaScriptSandbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JavaScriptSandbox.m; sourceTree = "<group>"; }; DE438CD82350934700DD541D /* JavaScriptSandbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JavaScriptSandbox.m; sourceTree = "<group>"; };
DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = "<group>"; }; DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = "<group>"; };
DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = "<group>"; }; DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = "<group>"; };
@ -223,6 +227,8 @@
DEFE535521FB2E8300011A3A /* ReactUtils.m */, DEFE535521FB2E8300011A3A /* ReactUtils.m */,
0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */, 0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */,
0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */, 0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */,
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */,
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */,
); );
path = src; path = src;
sourceTree = "<group>"; sourceTree = "<group>";
@ -303,6 +309,7 @@
DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */, DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */,
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */, DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */,
DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */, DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */,
C8AFD27F2462C613000293D2 /* InfoPlistUtil.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -482,6 +489,7 @@
0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */, 0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */,
0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */, 0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */,
0BCA49601EC4B6C600B793EE /* POSIX.m in Sources */, 0BCA49601EC4B6C600B793EE /* POSIX.m in Sources */,
C8AFD2802462C613000293D2 /* InfoPlistUtil.m in Sources */,
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */, C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */,
DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */, DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */,
0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */, 0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,

View File

@ -19,6 +19,8 @@
#import <React/RCTBridgeModule.h> #import <React/RCTBridgeModule.h>
#import <React/RCTLog.h> #import <React/RCTLog.h>
#import "InfoPlistUtil.h"
@interface AppInfo : NSObject<RCTBridgeModule> @interface AppInfo : NSObject<RCTBridgeModule>
@end @end
@ -67,13 +69,15 @@ RCT_EXPORT_MODULE();
buildNumber = @""; buildNumber = @"";
} }
BOOL isGoogleServiceEnabled = [InfoPlistUtil containsRealServiceInfoPlistInBundle:[NSBundle mainBundle]];
return @{ return @{
@"calendarEnabled": [NSNumber numberWithBool:calendarEnabled], @"calendarEnabled": [NSNumber numberWithBool:calendarEnabled],
@"buildNumber": buildNumber, @"buildNumber": buildNumber,
@"name": name, @"name": name,
@"sdkBundlePath": sdkBundlePath, @"sdkBundlePath": sdkBundlePath,
@"version": version @"version": version,
@"GOOGLE_SERVICES_ENABLED": [NSNumber numberWithBool:isGoogleServiceEnabled]
}; };
}; };
@end @end

View File

@ -0,0 +1,23 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* 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 <Foundation/Foundation.h>
@interface InfoPlistUtil : NSObject
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle;
@end

View File

@ -0,0 +1,52 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* 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 "InfoPlistUtil.h"
// Plist file name.
NSString *const kGoogleServiceInfoFileName = @"GoogleService-Info";
// Plist file type.
NSString *const kGoogleServiceInfoFileType = @"plist";
NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
@implementation InfoPlistUtil
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle {
NSString *bundlePath = bundle.bundlePath;
if (!bundlePath.length) {
return NO;
}
NSString *plistFilePath = [bundle pathForResource:kGoogleServiceInfoFileName
ofType:kGoogleServiceInfoFileType];
if (!plistFilePath.length) {
return NO;
}
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
if (!plist) {
return NO;
}
// Perform a very naive validation by checking to see if the plist has the dummy google app id
NSString *googleAppID = plist[kGoogleAppIDPlistKey];
if (!googleAppID.length) {
return NO;
}
return YES;
}
@end

View File

@ -20,6 +20,7 @@
#import <JitsiMeet/JitsiMeetConferenceOptions.h> #import <JitsiMeet/JitsiMeetConferenceOptions.h>
#import <JitsiMeet/JitsiMeetLogger.h> #import <JitsiMeet/JitsiMeetLogger.h>
#import <JitsiMeet/JitsiMeetBaseLogHandler.h> #import <JitsiMeet/JitsiMeetBaseLogHandler.h>
#import <JitsiMeet/InfoPlistUtil.h>
@interface JitsiMeet : NSObject @interface JitsiMeet : NSObject
@ -64,4 +65,6 @@
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions; - (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
- (BOOL)isCrashReportingDisabled;
@end @end

View File

@ -132,6 +132,11 @@
return nil; return nil;
} }
- (BOOL)isCrashReportingDisabled {
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"jitsi-default-preferences"];
return [userDefaults stringForKey:@"isCrashReportingDisabled"];
}
- (JitsiMeetConferenceOptions *)optionsFromUserActivity:(NSUserActivity *)userActivity { - (JitsiMeetConferenceOptions *)optionsFromUserActivity:(NSUserActivity *)userActivity {
NSString *activityType = userActivity.activityType; NSString *activityType = userActivity.activityType;

View File

@ -582,12 +582,15 @@
"settingsView": { "settingsView": {
"advanced": "Advanced", "advanced": "Advanced",
"alertOk": "OK", "alertOk": "OK",
"alertCancel": "Cancel",
"alertTitle": "Warning", "alertTitle": "Warning",
"alertURLText": "The entered server URL is invalid", "alertURLText": "The entered server URL is invalid",
"buildInfoSection": "Build Information", "buildInfoSection": "Build Information",
"conferenceSection": "Conference", "conferenceSection": "Conference",
"disableCallIntegration": "Disable native call integration", "disableCallIntegration": "Disable native call integration",
"disableP2P": "Disable Peer-To-Peer mode", "disableP2P": "Disable Peer-To-Peer mode",
"disableCrashReporting": "Disable crash reporting",
"disableCrashReportingWarning": "Are you sure you want to disable crash reporting? The setting will be applied after you restart the app.",
"displayName": "Display name", "displayName": "Display name",
"email": "Email", "email": "Email",
"header": "Settings", "header": "Settings",

5
package-lock.json generated
View File

@ -14827,6 +14827,11 @@
} }
} }
}, },
"react-native-default-preference": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/react-native-default-preference/-/react-native-default-preference-1.4.2.tgz",
"integrity": "sha512-kNhBLv8s6kO2gJJFEKM7qew7oRvJnygjgG1CU2ZEY6SlG5qsRX8z1Ms7z1Oo/XB7fVfyXrAoZDGhIvy+uiByrg=="
},
"react-native-immersive": { "react-native-immersive": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz", "resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",

View File

@ -72,6 +72,7 @@
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#902e6e92d6bae450a6052f76ba4d02f977ffd8f2", "react-native-calendar-events": "github:jitsi/react-native-calendar-events#902e6e92d6bae450a6052f76ba4d02f977ffd8f2",
"react-native-callstats": "3.61.0", "react-native-callstats": "3.61.0",
"react-native-collapsible": "1.5.1", "react-native-collapsible": "1.5.1",
"react-native-default-preference": "1.4.2",
"react-native-immersive": "2.0.0", "react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0", "react-native-keep-awake": "4.0.0",
"react-native-linear-gradient": "2.5.6", "react-native-linear-gradient": "2.5.6",

View File

@ -2,6 +2,8 @@
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import DefaultPreference from 'react-native-default-preference';
export * from './functions.any'; export * from './functions.any';
const { AudioMode } = NativeModules; const { AudioMode } = NativeModules;
@ -19,3 +21,17 @@ export function handleCallIntegrationChange(disabled: boolean) {
AudioMode.setUseConnectionService(!disabled); AudioMode.setUseConnectionService(!disabled);
} }
} }
/**
* Handles changes to the `disableCrashReporting` setting.
* Stores the value into platform specific default preference file, so at app
* start-up time it is retrieved on the native side and the crash reporting
* is enabled/disabled.
*
* @param {boolean} disabled - Whether crash reporting is disabled or not.
* @returns {void}
*/
export function handleCrashReportingChange(disabled: boolean) {
DefaultPreference.setName('jitsi-default-preferences').then(
DefaultPreference.set('isCrashReportingDisabled', disabled.toString()));
}

View File

@ -41,3 +41,13 @@ export function getCurrentOutputDeviceId(state: Object) {
*/ */
export function handleCallIntegrationChange(disabled: boolean) { // eslint-disable-line no-unused-vars export function handleCallIntegrationChange(disabled: boolean) { // eslint-disable-line no-unused-vars
} }
/**
* Handles changes to the `disableCrashReporting` setting.
* Noop on web.
*
* @param {boolean} disabled - Whether crash reporting is disabled or not.
* @returns {void}
*/
export function handleCrashReportingChange(disabled: boolean) { // eslint-disable-line no-unused-vars
}

View File

@ -9,7 +9,7 @@ import { getLocalParticipant, participantUpdated } from '../participants';
import { MiddlewareRegistry } from '../redux'; import { MiddlewareRegistry } from '../redux';
import { SETTINGS_UPDATED } from './actionTypes'; import { SETTINGS_UPDATED } from './actionTypes';
import { handleCallIntegrationChange } from './functions'; import { handleCallIntegrationChange, handleCrashReportingChange } from './functions';
/** /**
* The middleware of the feature base/settings. Distributes changes to the state * The middleware of the feature base/settings. Distributes changes to the state
@ -30,6 +30,7 @@ MiddlewareRegistry.register(store => next => action => {
_maybeHandleCallIntegrationChange(action); _maybeHandleCallIntegrationChange(action);
_maybeSetAudioOnly(store, action); _maybeSetAudioOnly(store, action);
_updateLocalParticipant(store, action); _updateLocalParticipant(store, action);
_maybeCrashReportingChange(action);
break; break;
case SET_LOCATION_URL: case SET_LOCATION_URL:
_updateLocalParticipantFromUrl(store); _updateLocalParticipantFromUrl(store);
@ -84,6 +85,19 @@ function _maybeHandleCallIntegrationChange({ settings: { disableCallIntegration
} }
} }
/**
* Handles a change in the `disableCrashReporting` setting.
*
* @param {Object} action - The redux action.
* @private
* @returns {void}
*/
function _maybeCrashReportingChange({ settings: { disableCrashReporting } }) {
if (typeof disableCrashReporting === 'boolean') {
handleCrashReportingChange(disableCrashReporting);
}
}
/** /**
* Updates {@code startAudioOnly} flag if it's updated in the settings. * Updates {@code startAudioOnly} flag if it's updated in the settings.
* *

View File

@ -24,6 +24,7 @@ const DEFAULT_STATE = {
avatarURL: undefined, avatarURL: undefined,
cameraDeviceId: undefined, cameraDeviceId: undefined,
disableCallIntegration: undefined, disableCallIntegration: undefined,
disableCrashReporting: undefined,
disableP2P: undefined, disableP2P: undefined,
displayName: undefined, displayName: undefined,
email: undefined, email: undefined,

View File

@ -36,6 +36,11 @@ type State = {
*/ */
disableP2P: boolean, disableP2P: boolean,
/**
* State variable for the disable crash reporting switch.
*/
disableCrashReporting: boolean,
/** /**
* State variable for the display name field. * State variable for the display name field.
*/ */
@ -84,6 +89,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
super(props); super(props);
const { const {
disableCallIntegration, disableCallIntegration,
disableCrashReporting,
disableP2P, disableP2P,
displayName, displayName,
email, email,
@ -94,6 +100,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
this.state = { this.state = {
disableCallIntegration, disableCallIntegration,
disableCrashReporting,
disableP2P, disableP2P,
displayName, displayName,
email, email,
@ -107,6 +114,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
this._onBlurServerURL = this._onBlurServerURL.bind(this); this._onBlurServerURL = this._onBlurServerURL.bind(this);
this._onClose = this._onClose.bind(this); this._onClose = this._onClose.bind(this);
this._onDisableCallIntegration = this._onDisableCallIntegration.bind(this); this._onDisableCallIntegration = this._onDisableCallIntegration.bind(this);
this._onDisableCrashReporting = this._onDisableCrashReporting.bind(this);
this._onDisableP2P = this._onDisableP2P.bind(this); this._onDisableP2P = this._onDisableP2P.bind(this);
this._onShowAdvanced = this._onShowAdvanced.bind(this); this._onShowAdvanced = this._onShowAdvanced.bind(this);
this._setURLFieldReference = this._setURLFieldReference.bind(this); this._setURLFieldReference = this._setURLFieldReference.bind(this);
@ -285,6 +293,24 @@ class SettingsView extends AbstractSettingsView<Props, State> {
}); });
} }
_onDisableCrashReporting: (boolean) => void;
/**
* Handles the disable crash reporting change event.
*
* @param {boolean} disableCrashReporting - The new value
* option.
* @private
* @returns {void}
*/
_onDisableCrashReporting(disableCrashReporting) {
if (disableCrashReporting) {
this._showCrashReportingDisableAlert();
} else {
this._disableCrashReporting(disableCrashReporting);
}
}
_onClose: () => void; _onClose: () => void;
/** /**
@ -367,7 +393,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
* @returns {React$Element} * @returns {React$Element}
*/ */
_renderAdvancedSettings() { _renderAdvancedSettings() {
const { disableCallIntegration, disableP2P, showAdvanced } = this.state; const { disableCallIntegration, disableP2P, disableCrashReporting, showAdvanced } = this.state;
if (!showAdvanced) { if (!showAdvanced) {
return ( return (
@ -397,6 +423,15 @@ class SettingsView extends AbstractSettingsView<Props, State> {
onValueChange = { this._onDisableP2P } onValueChange = { this._onDisableP2P }
value = { disableP2P } /> value = { disableP2P } />
</FormRow> </FormRow>
{AppInfo.GOOGLE_SERVICES_ENABLED && (
<FormRow
fieldSeparator = { true }
label = 'settingsView.disableCrashReporting'>
<Switch
onValueChange = { this._onDisableCrashReporting }
value = { disableCrashReporting } />
</FormRow>
)}
</> </>
); );
} }
@ -436,7 +471,41 @@ class SettingsView extends AbstractSettingsView<Props, State> {
); );
} }
/**
* Shows an alert warning the user about disabling crash reporting.
*
* @returns {void}
*/
_showCrashReportingDisableAlert() {
const { t } = this.props;
Alert.alert(
t('settingsView.alertTitle'),
t('settingsView.disableCrashReportingWarning'),
[
{
onPress: () => this._disableCrashReporting(true),
text: t('settingsView.alertOk')
},
{
text: t('settingsView.alertCancel')
}
]
);
}
_updateSettings: (Object) => void; _updateSettings: (Object) => void;
/**
* Updates the settings and sets state for disableCrashReporting.
*
* @param {boolean} disableCrashReporting - Whether crash reporting is disabled or not.
* @returns {void}
*/
_disableCrashReporting(disableCrashReporting) {
this._updateSettings({ disableCrashReporting });
this.setState({ disableCrashReporting });
}
} }
/** /**