Firebase
This commit is contained in:
parent
228485e3d0
commit
2354e93537
|
@ -5,8 +5,9 @@ apply plugin: "com.android.application"
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
if (!isFoss) {
|
if (!isFoss) {
|
||||||
apply plugin: 'com.google.firebase.crashlytics'
|
|
||||||
apply plugin: 'com.bugsnag.android.gradle'
|
apply plugin: 'com.bugsnag.android.gradle'
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
}
|
}
|
||||||
|
|
||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
|
@ -262,7 +263,7 @@ dependencies {
|
||||||
addUnimodulesDependencies()
|
addUnimodulesDependencies()
|
||||||
implementation project(':watermelondb')
|
implementation project(':watermelondb')
|
||||||
implementation project(':@react-native-community_viewpager')
|
implementation project(':@react-native-community_viewpager')
|
||||||
playImplementation project(':reactnativenotifications')
|
playImplementation project(':react-native-notifications')
|
||||||
playImplementation project(':@react-native-firebase_app')
|
playImplementation project(':@react-native-firebase_app')
|
||||||
playImplementation project(':@react-native-firebase_analytics')
|
playImplementation project(':@react-native-firebase_analytics')
|
||||||
playImplementation project(':@react-native-firebase_crashlytics')
|
playImplementation project(':@react-native-firebase_crashlytics')
|
||||||
|
@ -303,6 +304,3 @@ task copyDownloadableDepsToLibs(type: Copy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||||
if (!isFoss) {
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
|
||||||
}
|
|
||||||
|
|
|
@ -31,8 +31,8 @@ buildscript {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
if (isPlay) {
|
if (isPlay) {
|
||||||
classpath 'com.google.gms:google-services:4.2.0'
|
classpath 'com.google.gms:google-services:4.3.8'
|
||||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.0'
|
||||||
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
|
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
|
||||||
}
|
}
|
||||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||||
|
|
|
@ -4,8 +4,8 @@ includeUnimodulesProjects()
|
||||||
rootProject.name = 'RocketChatRN'
|
rootProject.name = 'RocketChatRN'
|
||||||
include ':watermelondb'
|
include ':watermelondb'
|
||||||
project(':watermelondb').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android')
|
project(':watermelondb').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android')
|
||||||
include ':reactnativenotifications'
|
include ':react-native-notifications'
|
||||||
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
|
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app')
|
||||||
include ':@react-native-community_viewpager'
|
include ':@react-native-community_viewpager'
|
||||||
project(':@react-native-community_viewpager').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/viewpager/android')
|
project(':@react-native-community_viewpager').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/viewpager/android')
|
||||||
include ':@react-native-firebase_app'
|
include ':@react-native-firebase_app'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import EJSON from 'ejson';
|
import EJSON from 'ejson';
|
||||||
import PushNotification from './push';
|
// import PushNotification from './push';
|
||||||
import store from '../../lib/createStore';
|
import store from '../../lib/createStore';
|
||||||
import { deepLinkingOpen } from '../../actions/deepLinking';
|
import { deepLinkingOpen } from '../../actions/deepLinking';
|
||||||
import { isFDroidBuild } from '../../constants/environment';
|
import { isFDroidBuild } from '../../constants/environment';
|
||||||
|
@ -36,13 +36,14 @@ export const onNotification = (notification) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDeviceToken = () => PushNotification.getDeviceToken();
|
export const getDeviceToken = () => {} // PushNotification.getDeviceToken();
|
||||||
export const setBadgeCount = count => PushNotification.setBadgeCount(count);
|
export const setBadgeCount = count => {} // PushNotification.setBadgeCount(count);
|
||||||
export const initializePushNotifications = () => {
|
export const initializePushNotifications = () => {
|
||||||
if (!isFDroidBuild) {
|
if (!isFDroidBuild) {
|
||||||
setBadgeCount();
|
setBadgeCount();
|
||||||
return PushNotification.configure({
|
// return PushNotification.configure({
|
||||||
onNotification
|
// onNotification
|
||||||
});
|
// });
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,7 @@ export const logEvent = (eventName, payload) => {
|
||||||
|
|
||||||
export const setCurrentScreen = (currentScreen) => {
|
export const setCurrentScreen = (currentScreen) => {
|
||||||
if (!isFDroidBuild) {
|
if (!isFDroidBuild) {
|
||||||
analytics().setCurrentScreen(currentScreen);
|
analytics().logScreenView({ screen_name: currentScreen });
|
||||||
leaveBreadcrumb(currentScreen, { type: 'navigation' });
|
leaveBreadcrumb(currentScreen, { type: 'navigation' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,6 +35,8 @@ target 'ShareRocketChatRN' do
|
||||||
pod 'RNFBApp', :path => '../node_modules/@react-native-firebase/app'
|
pod 'RNFBApp', :path => '../node_modules/@react-native-firebase/app'
|
||||||
pod 'RNFBAnalytics', :path => '../node_modules/@react-native-firebase/analytics'
|
pod 'RNFBAnalytics', :path => '../node_modules/@react-native-firebase/analytics'
|
||||||
pod 'RNFBCrashlytics', :path => '../node_modules/@react-native-firebase/crashlytics'
|
pod 'RNFBCrashlytics', :path => '../node_modules/@react-native-firebase/crashlytics'
|
||||||
|
$RNFirebaseAnalyticsWithoutAdIdSupport = true
|
||||||
|
|
||||||
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage'
|
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage'
|
||||||
pod 'RNCMaskedView', :path => '../node_modules/@react-native-community/masked-view'
|
pod 'RNCMaskedView', :path => '../node_modules/@react-native-community/masked-view'
|
||||||
pod 'RNFastImage', :path => '../node_modules/@rocket.chat/react-native-fast-image'
|
pod 'RNFastImage', :path => '../node_modules/@rocket.chat/react-native-fast-image'
|
||||||
|
|
183
ios/Podfile.lock
183
ios/Podfile.lock
|
@ -47,45 +47,51 @@ PODS:
|
||||||
- React-Core (= 0.63.4)
|
- React-Core (= 0.63.4)
|
||||||
- React-jsi (= 0.63.4)
|
- React-jsi (= 0.63.4)
|
||||||
- ReactCommon/turbomodule/core (= 0.63.4)
|
- ReactCommon/turbomodule/core (= 0.63.4)
|
||||||
- Firebase/Analytics (6.27.1):
|
- Firebase/AnalyticsWithoutAdIdSupport (8.1.1):
|
||||||
- Firebase/Core
|
|
||||||
- Firebase/Core (6.27.1):
|
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseAnalytics (= 6.6.2)
|
- FirebaseAnalytics/WithoutAdIdSupport (~> 8.0.0)
|
||||||
- Firebase/CoreOnly (6.27.1):
|
- Firebase/CoreOnly (8.1.1):
|
||||||
- FirebaseCore (= 6.8.1)
|
- FirebaseCore (= 8.1.0)
|
||||||
- Firebase/Crashlytics (6.27.1):
|
- Firebase/Crashlytics (8.1.1):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseCrashlytics (~> 4.2.0)
|
- FirebaseCrashlytics (~> 8.1.0)
|
||||||
- FirebaseAnalytics (6.6.2):
|
- FirebaseAnalytics/Base (8.0.0):
|
||||||
- FirebaseCore (~> 6.8)
|
- FirebaseCore (~> 8.0)
|
||||||
- FirebaseInstallations (~> 1.4)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleAppMeasurement (= 6.6.2)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
- GoogleUtilities/Network (~> 6.0)
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
- nanopb (~> 2.30908.0)
|
||||||
- nanopb (~> 1.30905.0)
|
- FirebaseAnalytics/WithoutAdIdSupport (8.0.0):
|
||||||
- FirebaseCore (6.8.1):
|
- FirebaseAnalytics/Base (= 8.0.0)
|
||||||
- FirebaseCoreDiagnostics (~> 1.3)
|
- FirebaseCore (~> 8.0)
|
||||||
- GoogleUtilities/Environment (~> 6.5)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleUtilities/Logger (~> 6.5)
|
- GoogleAppMeasurement/WithoutAdIdSupport (= 8.0.0)
|
||||||
- FirebaseCoreDiagnostics (1.4.0):
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleDataTransportCCTSupport (~> 3.1)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Environment (~> 6.5)
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
- GoogleUtilities/Logger (~> 6.5)
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- nanopb (~> 1.30905.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- FirebaseCrashlytics (4.2.0):
|
- FirebaseCore (8.1.0):
|
||||||
- FirebaseCore (~> 6.8)
|
- FirebaseCoreDiagnostics (~> 8.0)
|
||||||
- FirebaseInstallations (~> 1.1)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GoogleDataTransport (~> 6.1)
|
- GoogleUtilities/Logger (~> 7.4)
|
||||||
- GoogleDataTransportCCTSupport (~> 3.1)
|
- FirebaseCoreDiagnostics (8.1.0):
|
||||||
- nanopb (~> 1.30905.0)
|
- GoogleDataTransport (~> 9.0)
|
||||||
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
|
- GoogleUtilities/Logger (~> 7.4)
|
||||||
|
- nanopb (~> 2.30908.0)
|
||||||
|
- FirebaseCrashlytics (8.1.0):
|
||||||
|
- FirebaseCore (~> 8.0)
|
||||||
|
- FirebaseInstallations (~> 8.0)
|
||||||
|
- GoogleDataTransport (~> 9.0)
|
||||||
|
- nanopb (~> 2.30908.0)
|
||||||
- PromisesObjC (~> 1.2)
|
- PromisesObjC (~> 1.2)
|
||||||
- FirebaseInstallations (1.5.0):
|
- FirebaseInstallations (8.1.0):
|
||||||
- FirebaseCore (~> 6.8)
|
- FirebaseCore (~> 8.0)
|
||||||
- GoogleUtilities/Environment (~> 6.7)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
- GoogleUtilities/UserDefaults (~> 7.4)
|
||||||
- PromisesObjC (~> 1.2)
|
- PromisesObjC (~> 1.2)
|
||||||
- Flipper (0.54.0):
|
- Flipper (0.54.0):
|
||||||
- Flipper-Folly (~> 2.2)
|
- Flipper-Folly (~> 2.2)
|
||||||
|
@ -143,34 +149,34 @@ PODS:
|
||||||
- DoubleConversion
|
- DoubleConversion
|
||||||
- glog
|
- glog
|
||||||
- glog (0.3.5)
|
- glog (0.3.5)
|
||||||
- GoogleAppMeasurement (6.6.2):
|
- GoogleAppMeasurement/WithoutAdIdSupport (8.0.0):
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Network (~> 6.0)
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- nanopb (~> 1.30905.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- GoogleDataTransport (6.2.1)
|
- GoogleDataTransport (9.0.1):
|
||||||
- GoogleDataTransportCCTSupport (3.2.0):
|
- GoogleUtilities/Environment (~> 7.2)
|
||||||
- GoogleDataTransport (~> 6.1)
|
- nanopb (~> 2.30908.0)
|
||||||
- nanopb (~> 1.30905.0)
|
- PromisesObjC (~> 1.2)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (6.7.1):
|
- GoogleUtilities/AppDelegateSwizzler (7.4.1):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network
|
- GoogleUtilities/Network
|
||||||
- GoogleUtilities/Environment (6.7.1):
|
- GoogleUtilities/Environment (7.4.1):
|
||||||
- PromisesObjC (~> 1.2)
|
- PromisesObjC (~> 1.2)
|
||||||
- GoogleUtilities/Logger (6.7.1):
|
- GoogleUtilities/Logger (7.4.1):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/MethodSwizzler (6.7.1):
|
- GoogleUtilities/MethodSwizzler (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network (6.7.1):
|
- GoogleUtilities/Network (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- "GoogleUtilities/NSData+zlib"
|
- "GoogleUtilities/NSData+zlib"
|
||||||
- GoogleUtilities/Reachability
|
- GoogleUtilities/Reachability
|
||||||
- "GoogleUtilities/NSData+zlib (6.7.1)"
|
- "GoogleUtilities/NSData+zlib (7.4.1)"
|
||||||
- GoogleUtilities/Reachability (6.7.1):
|
- GoogleUtilities/Reachability (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/UserDefaults (6.7.1):
|
- GoogleUtilities/UserDefaults (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- JitsiMeetSDK (2.10.2)
|
- JitsiMeetSDK (2.10.2)
|
||||||
- KeyCommands (2.0.3):
|
- KeyCommands (2.0.3):
|
||||||
|
@ -187,15 +193,15 @@ PODS:
|
||||||
- MMKV (1.2.1):
|
- MMKV (1.2.1):
|
||||||
- MMKVCore (~> 1.2.1)
|
- MMKVCore (~> 1.2.1)
|
||||||
- MMKVCore (1.2.1)
|
- MMKVCore (1.2.1)
|
||||||
- nanopb (1.30905.0):
|
- nanopb (2.30908.0):
|
||||||
- nanopb/decode (= 1.30905.0)
|
- nanopb/decode (= 2.30908.0)
|
||||||
- nanopb/encode (= 1.30905.0)
|
- nanopb/encode (= 2.30908.0)
|
||||||
- nanopb/decode (1.30905.0)
|
- nanopb/decode (2.30908.0)
|
||||||
- nanopb/encode (1.30905.0)
|
- nanopb/encode (2.30908.0)
|
||||||
- OpenSSL-Universal (1.0.2.19):
|
- OpenSSL-Universal (1.0.2.19):
|
||||||
- OpenSSL-Universal/Static (= 1.0.2.19)
|
- OpenSSL-Universal/Static (= 1.0.2.19)
|
||||||
- OpenSSL-Universal/Static (1.0.2.19)
|
- OpenSSL-Universal/Static (1.0.2.19)
|
||||||
- PromisesObjC (1.2.9)
|
- PromisesObjC (1.2.12)
|
||||||
- RCTRequired (0.63.4)
|
- RCTRequired (0.63.4)
|
||||||
- RCTTypeSafety (0.63.4):
|
- RCTTypeSafety (0.63.4):
|
||||||
- FBLazyVector (= 0.63.4)
|
- FBLazyVector (= 0.63.4)
|
||||||
|
@ -382,8 +388,8 @@ PODS:
|
||||||
- React
|
- React
|
||||||
- react-native-netinfo (6.0.0):
|
- react-native-netinfo (6.0.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
- react-native-notifications (2.1.7):
|
- react-native-notifications (3.5.0):
|
||||||
- React
|
- React-Core
|
||||||
- react-native-orientation-locker (1.3.1):
|
- react-native-orientation-locker (1.3.1):
|
||||||
- React-Core
|
- React-Core
|
||||||
- react-native-restart (0.0.22):
|
- react-native-restart (0.0.22):
|
||||||
|
@ -483,17 +489,16 @@ PODS:
|
||||||
- React
|
- React
|
||||||
- SDWebImage (~> 5.0)
|
- SDWebImage (~> 5.0)
|
||||||
- SDWebImageWebPCoder (~> 0.4.1)
|
- SDWebImageWebPCoder (~> 0.4.1)
|
||||||
- RNFBAnalytics (7.3.1):
|
- RNFBAnalytics (12.1.0):
|
||||||
- Firebase/Analytics (~> 6.27.0)
|
- Firebase/AnalyticsWithoutAdIdSupport (= 8.1.1)
|
||||||
- React
|
- React-Core
|
||||||
- RNFBApp
|
- RNFBApp
|
||||||
- RNFBApp (8.2.0):
|
- RNFBApp (12.1.0):
|
||||||
- Firebase/CoreOnly (~> 6.27.0)
|
- Firebase/CoreOnly (= 8.1.1)
|
||||||
- React
|
- React-Core
|
||||||
- RNFBCrashlytics (8.1.2):
|
- RNFBCrashlytics (12.1.0):
|
||||||
- Firebase/Core (~> 6.27.0)
|
- Firebase/Crashlytics (= 8.1.1)
|
||||||
- Firebase/Crashlytics (~> 6.27.0)
|
- React-Core
|
||||||
- React
|
|
||||||
- RNFBApp
|
- RNFBApp
|
||||||
- RNGestureHandler (1.6.1):
|
- RNGestureHandler (1.6.1):
|
||||||
- React
|
- React
|
||||||
|
@ -678,7 +683,6 @@ SPEC REPOS:
|
||||||
- FlipperKit
|
- FlipperKit
|
||||||
- GoogleAppMeasurement
|
- GoogleAppMeasurement
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
- GoogleDataTransportCCTSupport
|
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
- libwebp
|
- libwebp
|
||||||
- MMKV
|
- MMKV
|
||||||
|
@ -899,12 +903,12 @@ SPEC CHECKSUMS:
|
||||||
EXWebBrowser: d37a5ffdea1b65947352bc001dd9f732463725d4
|
EXWebBrowser: d37a5ffdea1b65947352bc001dd9f732463725d4
|
||||||
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
||||||
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
||||||
Firebase: 919186c8e119dd9372a45fd1dd17a8a942bc1892
|
Firebase: 4bb49ae87756034cef870fa3c4006235eb46f475
|
||||||
FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4
|
FirebaseAnalytics: dcb92c7c9ef4fa7ffac276e8f87bd4fc8c97f1b8
|
||||||
FirebaseCore: 8cd4f8ea22075e0ee582849b1cf79d8816506085
|
FirebaseCore: 389c4ce9a7cce4a7e25eb22326b4bee0050557b2
|
||||||
FirebaseCoreDiagnostics: 4505e4d4009b1d93f605088ee7d7764d5f0d1c84
|
FirebaseCoreDiagnostics: 3e249cee3de5c5f9cfd6cc2a19997231286fec11
|
||||||
FirebaseCrashlytics: 7d0fa02ea8842cc4b2ab07b0735edafde1ad77d6
|
FirebaseCrashlytics: 1b55b3a718f9e20d59d96db46a4652d95a8ba1d2
|
||||||
FirebaseInstallations: 3c520c951305cbf9ca54eb891ff9e6d1fd384881
|
FirebaseInstallations: 7f31798a8198c354eadcb87176d2090b62edc187
|
||||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||||
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
||||||
|
@ -914,18 +918,17 @@ SPEC CHECKSUMS:
|
||||||
FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
|
FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
|
||||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||||
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
||||||
GoogleAppMeasurement: 8cd1f289d60e629cf16ab03363b9e89c776b9651
|
GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
|
||||||
GoogleDataTransport: 9a8a16f79feffc7f42096743de2a7c4815e84020
|
GoogleDataTransport: 04c3e9a480bbcaa2ec3f5d27f1cdeb6a92f20c8d
|
||||||
GoogleDataTransportCCTSupport: 489c1265d2c85b68187a83a911913d190012158d
|
GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
|
||||||
GoogleUtilities: e121a3867449ce16b0e35ddf1797ea7a389ffdf2
|
|
||||||
JitsiMeetSDK: ef6dd5cfa6d9badf009c7dba1a2c1365bfaae6b0
|
JitsiMeetSDK: ef6dd5cfa6d9badf009c7dba1a2c1365bfaae6b0
|
||||||
KeyCommands: f66c535f698ed14b3d3a4e58859d79a827ea907e
|
KeyCommands: f66c535f698ed14b3d3a4e58859d79a827ea907e
|
||||||
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
|
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
|
||||||
MMKV: 67253edee25a34edf332f91d73fa94a9e038b971
|
MMKV: 67253edee25a34edf332f91d73fa94a9e038b971
|
||||||
MMKVCore: fe398984acac1fa33f92795d1b5fd0a334c944af
|
MMKVCore: fe398984acac1fa33f92795d1b5fd0a334c944af
|
||||||
nanopb: c43f40fadfe79e8b8db116583945847910cbabc9
|
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||||
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
||||||
PromisesObjC: b48e0338dbbac2207e611750777895f7a5811b75
|
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||||
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
||||||
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
|
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
|
||||||
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
|
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
|
||||||
|
@ -945,7 +948,7 @@ SPEC CHECKSUMS:
|
||||||
react-native-jitsi-meet: f2407aca85566e031ee7b222e497ee5ecb6623de
|
react-native-jitsi-meet: f2407aca85566e031ee7b222e497ee5ecb6623de
|
||||||
react-native-mmkv-storage: 48729fe90e850ef2fdc9d3714b7030c7c51d82b0
|
react-native-mmkv-storage: 48729fe90e850ef2fdc9d3714b7030c7c51d82b0
|
||||||
react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d
|
react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d
|
||||||
react-native-notifications: ee8fd739853e72694f3af8b374c8ccb106b7b227
|
react-native-notifications: 89a73cd2cd2648e1734fa10e3507681c9e4f14de
|
||||||
react-native-orientation-locker: 998c0744e26624407dac068c04c605b4af7304a2
|
react-native-orientation-locker: 998c0744e26624407dac068c04c605b4af7304a2
|
||||||
react-native-restart: 733a51ad137f15b0f8dc34c4082e55af7da00979
|
react-native-restart: 733a51ad137f15b0f8dc34c4082e55af7da00979
|
||||||
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
|
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
|
||||||
|
@ -974,9 +977,9 @@ SPEC CHECKSUMS:
|
||||||
RNDateTimePicker: 7658208086d86d09e1627b5c34ba0cf237c60140
|
RNDateTimePicker: 7658208086d86d09e1627b5c34ba0cf237c60140
|
||||||
RNDeviceInfo: 8d3a29207835f972bce883723882980143270d55
|
RNDeviceInfo: 8d3a29207835f972bce883723882980143270d55
|
||||||
RNFastImage: f40d202ea2367239f71bc7cf11315f4bebab85b4
|
RNFastImage: f40d202ea2367239f71bc7cf11315f4bebab85b4
|
||||||
RNFBAnalytics: dae6d7b280ba61c96e1bbdd34aca3154388f025e
|
RNFBAnalytics: d8f885de70f3133ca1be101cb5f115e763dbd037
|
||||||
RNFBApp: 6fd8a7e757135d4168bf033a8812c241af7363a0
|
RNFBApp: 406bc9586c70ccf20504b4d3b54ac4341c98993f
|
||||||
RNFBCrashlytics: 88de72c2476b5868a892d9523b89b86c527c540e
|
RNFBCrashlytics: 963a2757f6a52e37ae50adab5832162a7d81f98f
|
||||||
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
|
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
|
||||||
RNImageCropPicker: 38865ab4af1b0b2146ad66061196bc0184946855
|
RNImageCropPicker: 38865ab4af1b0b2146ad66061196bc0184946855
|
||||||
RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b
|
RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b
|
||||||
|
@ -1003,6 +1006,6 @@ SPEC CHECKSUMS:
|
||||||
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
||||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||||
|
|
||||||
PODFILE CHECKSUM: 0351d0973911a397f1cb4e45f0b0f590b14816e3
|
PODFILE CHECKSUM: 31a91f8b33d73b8680ec7d53c60c76a243f70a20
|
||||||
|
|
||||||
COCOAPODS: 1.10.1
|
COCOAPODS: 1.10.1
|
||||||
|
|
|
@ -22,6 +22,14 @@
|
||||||
#import <FirebaseAnalytics/FirebaseAnalytics.h>
|
#import <FirebaseAnalytics/FirebaseAnalytics.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<FirebaseAppCheck/FirebaseAppCheck.h>)
|
||||||
|
#import <FirebaseAppCheck/FirebaseAppCheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<FirebaseAppDistribution/FirebaseAppDistribution.h>)
|
||||||
|
#import <FirebaseAppDistribution/FirebaseAppDistribution.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseAuth/FirebaseAuth.h>)
|
#if __has_include(<FirebaseAuth/FirebaseAuth.h>)
|
||||||
#import <FirebaseAuth/FirebaseAuth.h>
|
#import <FirebaseAuth/FirebaseAuth.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -36,13 +44,6 @@
|
||||||
|
|
||||||
#if __has_include(<FirebaseDynamicLinks/FirebaseDynamicLinks.h>)
|
#if __has_include(<FirebaseDynamicLinks/FirebaseDynamicLinks.h>)
|
||||||
#import <FirebaseDynamicLinks/FirebaseDynamicLinks.h>
|
#import <FirebaseDynamicLinks/FirebaseDynamicLinks.h>
|
||||||
#if !__has_include(<FirebaseAnalytics/FirebaseAnalytics.h>)
|
|
||||||
#ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#warning "FirebaseAnalytics.framework is not included in your target. Please add \
|
|
||||||
`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \
|
|
||||||
Firebase Dynamic Links works as intended."
|
|
||||||
#endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||||
|
@ -55,118 +56,26 @@ Firebase Dynamic Links works as intended."
|
||||||
|
|
||||||
#if __has_include(<FirebaseInAppMessaging/FirebaseInAppMessaging.h>)
|
#if __has_include(<FirebaseInAppMessaging/FirebaseInAppMessaging.h>)
|
||||||
#import <FirebaseInAppMessaging/FirebaseInAppMessaging.h>
|
#import <FirebaseInAppMessaging/FirebaseInAppMessaging.h>
|
||||||
#if !__has_include(<FirebaseAnalytics/FirebaseAnalytics.h>)
|
|
||||||
#ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#warning "FirebaseAnalytics.framework is not included in your target. Please add \
|
|
||||||
`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \
|
|
||||||
Firebase In App Messaging works as intended."
|
|
||||||
#endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseInstanceID/FirebaseInstanceID.h>)
|
#if __has_include(<FirebaseInstallations/FirebaseInstallations.h>)
|
||||||
#import <FirebaseInstanceID/FirebaseInstanceID.h>
|
#import <FirebaseInstallations/FirebaseInstallations.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseMessaging/FirebaseMessaging.h>)
|
#if __has_include(<FirebaseMessaging/FirebaseMessaging.h>)
|
||||||
#import <FirebaseMessaging/FirebaseMessaging.h>
|
#import <FirebaseMessaging/FirebaseMessaging.h>
|
||||||
#if !__has_include(<FirebaseAnalytics/FirebaseAnalytics.h>)
|
|
||||||
#ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#warning "FirebaseAnalytics.framework is not included in your target. Please add \
|
|
||||||
`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \
|
|
||||||
Firebase Messaging works as intended."
|
|
||||||
#endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLCommon/FirebaseMLCommon.h>)
|
|
||||||
#import <FirebaseMLCommon/FirebaseMLCommon.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLModelInterpreter/FirebaseMLModelInterpreter.h>)
|
|
||||||
#import <FirebaseMLModelInterpreter/FirebaseMLModelInterpreter.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLNLLanguageID/FirebaseMLNLLanguageID.h>)
|
|
||||||
#import <FirebaseMLNLLanguageID/FirebaseMLNLLanguageID.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLNLSmartReply/FirebaseMLNLSmartReply.h>)
|
|
||||||
#import <FirebaseMLNLSmartReply/FirebaseMLNLSmartReply.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLNLTranslate/FirebaseMLNLTranslate.h>)
|
|
||||||
#import <FirebaseMLNLTranslate/FirebaseMLNLTranslate.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLNaturalLanguage/FirebaseMLNaturalLanguage.h>)
|
|
||||||
#import <FirebaseMLNaturalLanguage/FirebaseMLNaturalLanguage.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVision/FirebaseMLVision.h>)
|
|
||||||
#import <FirebaseMLVision/FirebaseMLVision.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVisionAutoML/FirebaseMLVisionAutoML.h>)
|
|
||||||
#import <FirebaseMLVisionAutoML/FirebaseMLVisionAutoML.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVisionBarcodeModel/FirebaseMLVisionBarcodeModel.h>)
|
|
||||||
#import <FirebaseMLVisionBarcodeModel/FirebaseMLVisionBarcodeModel.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVisionFaceModel/FirebaseMLVisionFaceModel.h>)
|
|
||||||
#import <FirebaseMLVisionFaceModel/FirebaseMLVisionFaceModel.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVisionLabelModel/FirebaseMLVisionLabelModel.h>)
|
|
||||||
#import <FirebaseMLVisionLabelModel/FirebaseMLVisionLabelModel.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVisionObjectDetection/FirebaseMLVisionObjectDetection.h>)
|
|
||||||
#import <FirebaseMLVisionObjectDetection/FirebaseMLVisionObjectDetection.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<FirebaseMLVisionTextModel/FirebaseMLVisionTextModel.h>)
|
|
||||||
#import <FirebaseMLVisionTextModel/FirebaseMLVisionTextModel.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebasePerformance/FirebasePerformance.h>)
|
#if __has_include(<FirebasePerformance/FirebasePerformance.h>)
|
||||||
#import <FirebasePerformance/FirebasePerformance.h>
|
#import <FirebasePerformance/FirebasePerformance.h>
|
||||||
#if !__has_include(<FirebaseAnalytics/FirebaseAnalytics.h>)
|
|
||||||
#ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#warning "FirebaseAnalytics.framework is not included in your target. Please add \
|
|
||||||
`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \
|
|
||||||
Firebase Performance works as intended."
|
|
||||||
#endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseRemoteConfig/FirebaseRemoteConfig.h>)
|
#if __has_include(<FirebaseRemoteConfig/FirebaseRemoteConfig.h>)
|
||||||
#import <FirebaseRemoteConfig/FirebaseRemoteConfig.h>
|
#import <FirebaseRemoteConfig/FirebaseRemoteConfig.h>
|
||||||
#if !__has_include(<FirebaseAnalytics/FirebaseAnalytics.h>)
|
|
||||||
#ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#warning "FirebaseAnalytics.framework is not included in your target. Please add \
|
|
||||||
`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \
|
|
||||||
Firebase Remote Config works as intended."
|
|
||||||
#endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
|
#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
|
||||||
#import <FirebaseStorage/FirebaseStorage.h>
|
#import <FirebaseStorage/FirebaseStorage.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<GoogleMobileAds/GoogleMobileAds.h>)
|
|
||||||
#import <GoogleMobileAds/GoogleMobileAds.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<Fabric/Fabric.h>)
|
|
||||||
#import <Fabric/Fabric.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<Crashlytics/Crashlytics.h>)
|
|
||||||
#import <Crashlytics/Crashlytics.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // defined(__has_include)
|
#endif // defined(__has_include)
|
||||||
|
|
|
@ -3,8 +3,12 @@
|
||||||
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
|
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
|
||||||
|
|
||||||
[![Actions Status][gh-abtesting-badge]][gh-actions]
|
[![Actions Status][gh-abtesting-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-appcheck-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-appdistribution-badge]][gh-actions]
|
||||||
[![Actions Status][gh-auth-badge]][gh-actions]
|
[![Actions Status][gh-auth-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-cocoapods-integration-badge]][gh-actions]
|
||||||
[![Actions Status][gh-core-badge]][gh-actions]
|
[![Actions Status][gh-core-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-core-diagnostics-badge]][gh-actions]
|
||||||
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
||||||
[![Actions Status][gh-database-badge]][gh-actions]
|
[![Actions Status][gh-database-badge]][gh-actions]
|
||||||
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
||||||
|
@ -12,9 +16,13 @@
|
||||||
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
||||||
[![Actions Status][gh-firestore-badge]][gh-actions]
|
[![Actions Status][gh-firestore-badge]][gh-actions]
|
||||||
[![Actions Status][gh-functions-badge]][gh-actions]
|
[![Actions Status][gh-functions-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-google-utilities-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-google-utilities-components-badge]][gh-actions]
|
||||||
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
|
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
|
||||||
[![Actions Status][gh-interop-badge]][gh-actions]
|
[![Actions Status][gh-interop-badge]][gh-actions]
|
||||||
[![Actions Status][gh-messaging-badge]][gh-actions]
|
[![Actions Status][gh-messaging-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-mlmodeldownloader-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-performance-badge]][gh-actions]
|
||||||
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
|
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
|
||||||
[![Actions Status][gh-storage-badge]][gh-actions]
|
[![Actions Status][gh-storage-badge]][gh-actions]
|
||||||
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
||||||
|
@ -23,21 +31,23 @@
|
||||||
|
|
||||||
# Firebase Apple Open Source Development
|
# Firebase Apple Open Source Development
|
||||||
|
|
||||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
|
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
|
||||||
FirebasePerformance, and FirebaseML.
|
and FirebaseML.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
|
||||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
|
||||||
a set of utilities used by Firebase and other Google products.
|
|
||||||
|
|
||||||
Firebase is an app development platform with tools to help you build, grow and
|
Firebase is an app development platform with tools to help you build, grow and
|
||||||
monetize your app. More information about Firebase can be found at
|
monetize your app. More information about Firebase can be found at
|
||||||
[https://firebase.google.com](https://firebase.google.com).
|
[https://firebase.google.com](https://firebase.google.com).
|
||||||
|
|
||||||
|
The repository also includes GoogleUtilities and GoogleDataTransport source
|
||||||
|
which are utilities used by Firebase and other Google products.
|
||||||
|
|
||||||
|
**Note** _FirebaseCombineSwift_ contains support for Apple's Combine framework. This module is currently under development, and not yet supported for use in production environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
See the three subsections for details about three different installation methods.
|
See the subsections below for details about the different installation methods.
|
||||||
1. [Standard pod install](README.md#standard-pod-install)
|
1. [Standard pod install](README.md#standard-pod-install)
|
||||||
|
1. [Swift Package Manager](SwiftPackageManager.md)
|
||||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||||
1. [Experimental Carthage](README.md#carthage-ios-only)
|
1. [Experimental Carthage](README.md#carthage-ios-only)
|
||||||
|
|
||||||
|
@ -46,11 +56,12 @@ See the three subsections for details about three different installation methods
|
||||||
Go to
|
Go to
|
||||||
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
||||||
|
|
||||||
### Installing from GitHub
|
### Swift Package Manager
|
||||||
|
|
||||||
For releases starting with 5.0.0, the source for each release is also deployed
|
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
|
||||||
to CocoaPods master and available via standard
|
found at [SwiftPackageManager.md](SwiftPackageManager.md).
|
||||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
|
||||||
|
### Installing from GitHub
|
||||||
|
|
||||||
These instructions can be used to access the Firebase repo at other branches,
|
These instructions can be used to access the Firebase repo at other branches,
|
||||||
tags, or commits.
|
tags, or commits.
|
||||||
|
@ -67,14 +78,14 @@ All of the official releases are tagged in this repo and available via CocoaPods
|
||||||
source snapshot or unreleased branch, use Podfile directives like the following:
|
source snapshot or unreleased branch, use Podfile directives like the following:
|
||||||
|
|
||||||
To access FirebaseFirestore via a branch:
|
To access FirebaseFirestore via a branch:
|
||||||
```
|
```ruby
|
||||||
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
```
|
```
|
||||||
|
|
||||||
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
||||||
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
```
|
```
|
||||||
|
@ -82,12 +93,8 @@ pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
### Carthage (iOS only)
|
### Carthage (iOS only)
|
||||||
|
|
||||||
Instructions for the experimental Carthage distribution are at
|
Instructions for the experimental Carthage distribution are at
|
||||||
[Carthage](Carthage.md).
|
[Carthage](Carthage.md). If you have a new Mac with an Apple silicon chip, please see
|
||||||
|
[these instructions](AppleSilicon.md).
|
||||||
### Rome
|
|
||||||
|
|
||||||
Instructions for installing binary frameworks via
|
|
||||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
|
||||||
|
|
||||||
### Using Firebase from a Framework or a library
|
### Using Firebase from a Framework or a library
|
||||||
|
|
||||||
|
@ -98,13 +105,22 @@ Instructions for installing binary frameworks via
|
||||||
To develop Firebase software in this repository, ensure that you have at least
|
To develop Firebase software in this repository, ensure that you have at least
|
||||||
the following software:
|
the following software:
|
||||||
|
|
||||||
* Xcode 10.3 (or later)
|
* Xcode 12.2 (or later)
|
||||||
* CocoaPods 1.7.2 (or later)
|
|
||||||
|
CocoaPods is still the canonical way to develop, but much of the repo now supports
|
||||||
|
development with Swift Package Manager.
|
||||||
|
|
||||||
|
### CocoaPods
|
||||||
|
|
||||||
|
Install
|
||||||
|
* CocoaPods 1.10.0 (or later)
|
||||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||||
|
|
||||||
For the pod that you want to develop:
|
For the pod that you want to develop:
|
||||||
|
|
||||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
```ruby
|
||||||
|
pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios
|
||||||
|
```
|
||||||
|
|
||||||
Note: If the CocoaPods cache is out of date, you may need to run
|
Note: If the CocoaPods cache is out of date, you may need to run
|
||||||
`pod repo update` before the `pod gen` command.
|
`pod repo update` before the `pod gen` command.
|
||||||
|
@ -116,7 +132,7 @@ CocoaPods workspaces.
|
||||||
Firestore has a self contained Xcode project. See
|
Firestore has a self contained Xcode project. See
|
||||||
[Firestore/README.md](Firestore/README.md).
|
[Firestore/README.md](Firestore/README.md).
|
||||||
|
|
||||||
### Development for Catalyst
|
#### Development for Catalyst
|
||||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||||
* Check the Mac box in the App-iOS Build Settings
|
* Check the Mac box in the App-iOS Build Settings
|
||||||
* Sign the App in the Settings Signing & Capabilities tab
|
* Sign the App in the Settings Signing & Capabilities tab
|
||||||
|
@ -125,6 +141,18 @@ Firestore has a self contained Xcode project. See
|
||||||
* Select the Unit-unit scheme
|
* Select the Unit-unit scheme
|
||||||
* Run it to build and test
|
* Run it to build and test
|
||||||
|
|
||||||
|
Alternatively disable signing in each target:
|
||||||
|
* Go to Build Settings tab
|
||||||
|
* Click `+`
|
||||||
|
* Select `Add User-Defined Setting`
|
||||||
|
* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO`
|
||||||
|
|
||||||
|
### Swift Package Manager
|
||||||
|
* `open Package.swift` or double click `Package.swift` in Finder.
|
||||||
|
* Xcode will open the project
|
||||||
|
* Choose a scheme for a library to build or test suite to run
|
||||||
|
* Choose a target platform by selecting the run destination along with the scheme
|
||||||
|
|
||||||
### Adding a New Firebase Pod
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
See [AddNewPod.md](AddNewPod.md).
|
See [AddNewPod.md](AddNewPod.md).
|
||||||
|
@ -136,40 +164,24 @@ See [HeadersImports.md](HeadersImports.md).
|
||||||
### Code Formatting
|
### Code Formatting
|
||||||
|
|
||||||
To ensure that the code is formatted consistently, run the script
|
To ensure that the code is formatted consistently, run the script
|
||||||
[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
|
[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh)
|
||||||
before creating a PR.
|
before creating a PR.
|
||||||
|
|
||||||
Travis will verify that any code changes are done in a style compliant way. Install
|
GitHub Actions will verify that any code changes are done in a style compliant
|
||||||
`clang-format` and `swiftformat`.
|
way. Install `clang-format` and `mint`:
|
||||||
These commands will get the right versions:
|
|
||||||
|
|
||||||
|
```console
|
||||||
|
brew install clang-format@12
|
||||||
|
brew install mint
|
||||||
```
|
```
|
||||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/c6f1cbd/Formula/clang-format.rb
|
|
||||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/c13eda8/Formula/swiftformat.rb
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: if you already have a newer version of these installed you may need to
|
|
||||||
`brew switch` to this version.
|
|
||||||
|
|
||||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
|
||||||
match the versions in the CI failure logs
|
|
||||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
|
||||||
|
|
||||||
### Running Unit Tests
|
### Running Unit Tests
|
||||||
|
|
||||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||||
|
|
||||||
#### Viewing Code Coverage (Deprecated)
|
|
||||||
|
|
||||||
First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
|
|
||||||
|
|
||||||
After running the `AllUnitTests_iOS` scheme in Xcode, execute
|
|
||||||
`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
|
|
||||||
at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
|
|
||||||
|
|
||||||
### Running Sample Apps
|
### Running Sample Apps
|
||||||
In order to run the sample apps and integration tests, you'll need valid
|
In order to run the sample apps and integration tests, you'll need a valid
|
||||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist
|
||||||
files without real values, but can be replaced with real plist files. To get your own
|
files without real values, but can be replaced with real plist files. To get your own
|
||||||
`GoogleService-Info.plist` files:
|
`GoogleService-Info.plist` files:
|
||||||
|
|
||||||
|
@ -177,12 +189,11 @@ files without real values, but can be replaced with real plist files. To get you
|
||||||
2. Create a new Firebase project, if you don't already have one
|
2. Create a new Firebase project, if you don't already have one
|
||||||
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
||||||
identifier (e.g. `com.google.Database-Example`)
|
identifier (e.g. `com.google.Database-Example`)
|
||||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
|
||||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
|
||||||
|
|
||||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
### Coverage Report Generation
|
||||||
special Apple capabilities, and you will have to change the sample app to use a unique bundle
|
|
||||||
identifier that you can control in your own Apple Developer account.
|
See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md).
|
||||||
|
|
||||||
## Specific Component Instructions
|
## Specific Component Instructions
|
||||||
See the sections below for any special instructions for those components.
|
See the sections below for any special instructions for those components.
|
||||||
|
@ -202,10 +213,16 @@ To run against a local emulator instance, invoke `./scripts/run_database_emulato
|
||||||
running the integration test.
|
running the integration test.
|
||||||
|
|
||||||
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
|
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
|
||||||
`Example/Database/App/GoogleService-Info.plist`. Your Security Rule must be set to
|
`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to
|
||||||
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
|
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
|
||||||
running.
|
running.
|
||||||
|
|
||||||
|
### Firebase Performance Monitoring
|
||||||
|
If you're doing specific Firebase Performance Monitoring development, see
|
||||||
|
[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK
|
||||||
|
and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about
|
||||||
|
integrating Performance with the dev test App.
|
||||||
|
|
||||||
### Firebase Storage
|
### Firebase Storage
|
||||||
|
|
||||||
To run the Storage Integration tests, follow the instructions in
|
To run the Storage Integration tests, follow the instructions in
|
||||||
|
@ -219,7 +236,8 @@ In order to actually test receiving push notifications, you will need to:
|
||||||
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
||||||
account, and enable that App ID for push notifications.
|
account, and enable that App ID for push notifications.
|
||||||
2. You'll also need to
|
2. You'll also need to
|
||||||
[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
[upload your APNs Provider Authentication Key or certificate to the
|
||||||
|
Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
||||||
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
||||||
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
||||||
|
|
||||||
|
@ -229,43 +247,39 @@ The iOS Simulator cannot register for remote notifications, and will not receive
|
||||||
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
||||||
physical device.
|
physical device.
|
||||||
|
|
||||||
## Community Supported Efforts
|
## Building with Firebase on Apple platforms
|
||||||
|
|
||||||
|
At this time, not all of Firebase's products are available across all Apple platforms. However,
|
||||||
|
Firebase is constantly evolving and community supported efforts have helped expand Firebase's support.
|
||||||
|
To keep up with the latest info regarding Firebase's support across Apple platforms, refer to
|
||||||
|
[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform)
|
||||||
|
in Firebase's documentation.
|
||||||
|
|
||||||
|
### Community Supported Efforts
|
||||||
|
|
||||||
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
||||||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||||
participate in the Firebase community.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### tvOS, macOS, watchOS and Catalyst
|
#### tvOS, macOS, watchOS and Catalyst
|
||||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and
|
||||||
tvOS, macOS, watchOS and Catalyst.
|
work on tvOS, macOS, watchOS and Catalyst.
|
||||||
|
|
||||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
For tvOS, see the [Sample](Example/tvOSSample).
|
||||||
For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
|
For watchOS, currently only Messaging, Storage and Crashlytics (and their dependencies) have limited
|
||||||
[Independent Watch App Sample](Example/watchOSSample).
|
support. See the [Independent Watch App Sample](Example/watchOSSample).
|
||||||
|
|
||||||
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and this
|
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and
|
||||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
this repository is actively developed primarily for iOS. While we can catch basic unit test issues
|
||||||
Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
|
with GitHub Actions, there may be some changes where the SDK no longer works as expected on macOS,
|
||||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
tvOS or watchOS. If you encounter this, please
|
||||||
|
[file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||||
|
|
||||||
During app setup in the console, you may get to a step that mentions something like "Checking if the app
|
During app setup in the console, you may get to a step that mentions something like "Checking if the
|
||||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
|
app has communicated with our servers". This relies on Analytics and will not work on
|
||||||
|
macOS/tvOS/watchOS/Catalyst.
|
||||||
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
||||||
|
|
||||||
To install, add a subset of the following to the Podfile:
|
|
||||||
|
|
||||||
```
|
|
||||||
pod 'Firebase/ABTesting' # No watchOS support yet
|
|
||||||
pod 'Firebase/Auth' # No watchOS support yet
|
|
||||||
pod 'Firebase/Crashlytics' # No watchOS support yet
|
|
||||||
pod 'Firebase/Database' # No watchOS support yet
|
|
||||||
pod 'Firebase/Firestore' # No watchOS support yet
|
|
||||||
pod 'Firebase/Functions' # No watchOS support yet
|
|
||||||
pod 'Firebase/Messaging'
|
|
||||||
pod 'Firebase/RemoteConfig' # No watchOS support yet
|
|
||||||
pod 'Firebase/Storage'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Additional Catalyst Notes
|
#### Additional Catalyst Notes
|
||||||
|
|
||||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||||
|
@ -273,6 +287,10 @@ to Build Settings.
|
||||||
* FirebaseFirestore requires signing the
|
* FirebaseFirestore requires signing the
|
||||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||||
|
|
||||||
|
#### Additional Crashlytics Notes
|
||||||
|
* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are
|
||||||
|
not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded)
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
@ -293,8 +311,12 @@ Your use of Firebase is governed by the
|
||||||
|
|
||||||
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
|
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
|
||||||
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
|
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
|
||||||
|
[gh-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg
|
||||||
|
[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg
|
||||||
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
|
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
|
||||||
|
[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg
|
||||||
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
|
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
|
||||||
|
[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/badge.svg
|
||||||
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
|
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
|
||||||
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
|
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
|
||||||
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
|
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
|
||||||
|
@ -302,9 +324,13 @@ Your use of Firebase is governed by the
|
||||||
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
|
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
|
||||||
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
|
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
|
||||||
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
|
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
|
||||||
|
[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg
|
||||||
|
[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/badge.svg
|
||||||
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
|
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
|
||||||
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
|
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
|
||||||
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
|
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
|
||||||
|
[gh-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg
|
||||||
|
[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/badge.svg
|
||||||
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
|
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
|
||||||
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
|
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
|
||||||
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
|
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
|
||||||
|
|
Binary file not shown.
|
@ -1,11 +0,0 @@
|
||||||
framework module FIRAnalyticsConnector {
|
|
||||||
export *
|
|
||||||
module * { export * }
|
|
||||||
link "sqlite3"
|
|
||||||
link "z"
|
|
||||||
link framework "CoreData"
|
|
||||||
link framework "Security"
|
|
||||||
link framework "StoreKit"
|
|
||||||
link framework "SystemConfiguration"
|
|
||||||
link framework "UIKit"
|
|
||||||
}
|
|
Binary file not shown.
42
ios/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist
generated
Normal file
42
ios/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist
generated
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>AvailableLibraries</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64_i386_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>FirebaseAnalytics.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>i386</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64_armv7</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>FirebaseAnalytics.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XFWK</string>
|
||||||
|
<key>XCFrameworkFormatVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "FIRAnalytics.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and
|
||||||
|
/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status.
|
||||||
|
typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType);
|
||||||
|
extern FIRConsentType const FIRConsentTypeAdStorage;
|
||||||
|
extern FIRConsentType const FIRConsentTypeAnalyticsStorage;
|
||||||
|
|
||||||
|
/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and
|
||||||
|
/// `ConsentStatus.denied`.
|
||||||
|
typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus);
|
||||||
|
extern FIRConsentStatus const FIRConsentStatusDenied;
|
||||||
|
extern FIRConsentStatus const FIRConsentStatusGranted;
|
||||||
|
|
||||||
|
/// Sets the applicable end user consent state.
|
||||||
|
@interface FIRAnalytics (Consent)
|
||||||
|
|
||||||
|
/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this
|
||||||
|
/// device. Use the consent settings to specify individual consent type values. Settings are
|
||||||
|
/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`.
|
||||||
|
///
|
||||||
|
/// @param consentSettings An NSDictionary of consent types. Supported consent type keys are
|
||||||
|
/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are
|
||||||
|
/// `ConsentStatus.granted` and `ConsentStatus.denied`.
|
||||||
|
+ (void)setConsent:(NSDictionary<FIRConsentType, FIRConsentStatus> *)consentSettings;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -25,22 +25,34 @@ NS_SWIFT_NAME(Analytics)
|
||||||
/// <li>ad_activeview</li>
|
/// <li>ad_activeview</li>
|
||||||
/// <li>ad_click</li>
|
/// <li>ad_click</li>
|
||||||
/// <li>ad_exposure</li>
|
/// <li>ad_exposure</li>
|
||||||
/// <li>ad_impression</li>
|
|
||||||
/// <li>ad_query</li>
|
/// <li>ad_query</li>
|
||||||
|
/// <li>ad_reward</li>
|
||||||
/// <li>adunit_exposure</li>
|
/// <li>adunit_exposure</li>
|
||||||
|
/// <li>app_background</li>
|
||||||
/// <li>app_clear_data</li>
|
/// <li>app_clear_data</li>
|
||||||
|
/// <li>app_exception</li>
|
||||||
/// <li>app_remove</li>
|
/// <li>app_remove</li>
|
||||||
|
/// <li>app_store_refund</li>
|
||||||
|
/// <li>app_store_subscription_cancel</li>
|
||||||
|
/// <li>app_store_subscription_convert</li>
|
||||||
|
/// <li>app_store_subscription_renew</li>
|
||||||
/// <li>app_update</li>
|
/// <li>app_update</li>
|
||||||
|
/// <li>app_upgrade</li>
|
||||||
|
/// <li>dynamic_link_app_open</li>
|
||||||
|
/// <li>dynamic_link_app_update</li>
|
||||||
|
/// <li>dynamic_link_first_open</li>
|
||||||
/// <li>error</li>
|
/// <li>error</li>
|
||||||
|
/// <li>firebase_campaign</li>
|
||||||
/// <li>first_open</li>
|
/// <li>first_open</li>
|
||||||
|
/// <li>first_visit</li>
|
||||||
/// <li>in_app_purchase</li>
|
/// <li>in_app_purchase</li>
|
||||||
/// <li>notification_dismiss</li>
|
/// <li>notification_dismiss</li>
|
||||||
/// <li>notification_foreground</li>
|
/// <li>notification_foreground</li>
|
||||||
/// <li>notification_open</li>
|
/// <li>notification_open</li>
|
||||||
/// <li>notification_receive</li>
|
/// <li>notification_receive</li>
|
||||||
/// <li>os_update</li>
|
/// <li>os_update</li>
|
||||||
/// <li>screen_view</li>
|
|
||||||
/// <li>session_start</li>
|
/// <li>session_start</li>
|
||||||
|
/// <li>session_start_with_rollout</li>
|
||||||
/// <li>user_engagement</li>
|
/// <li>user_engagement</li>
|
||||||
/// </ul>
|
/// </ul>
|
||||||
///
|
///
|
||||||
|
@ -49,7 +61,7 @@ NS_SWIFT_NAME(Analytics)
|
||||||
/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_",
|
/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_",
|
||||||
/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are
|
/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are
|
||||||
/// case-sensitive and that logging two events whose names differ only in case will result in
|
/// case-sensitive and that logging two events whose names differ only in case will result in
|
||||||
/// two distinct events.
|
/// two distinct events. To manually log screen view events, use the `screen_view` event name.
|
||||||
/// @param parameters The dictionary of event parameters. Passing nil indicates that the event has
|
/// @param parameters The dictionary of event parameters. Passing nil indicates that the event has
|
||||||
/// no parameters. Parameter names can be up to 40 characters long and must start with an
|
/// no parameters. Parameter names can be up to 40 characters long and must start with an
|
||||||
/// alphabetic character and contain only alphanumeric characters and underscores. Only NSString
|
/// alphabetic character and contain only alphanumeric characters and underscores. Only NSString
|
||||||
|
@ -85,33 +97,6 @@ NS_SWIFT_NAME(Analytics)
|
||||||
/// non-empty and no more than 256 characters long. Setting userID to nil removes the user ID.
|
/// non-empty and no more than 256 characters long. Setting userID to nil removes the user ID.
|
||||||
+ (void)setUserID:(nullable NSString *)userID;
|
+ (void)setUserID:(nullable NSString *)userID;
|
||||||
|
|
||||||
/// Sets the current screen name, which specifies the current visual context in your app. This helps
|
|
||||||
/// identify the areas in your app where users spend their time and how they interact with your app.
|
|
||||||
/// Must be called on the main thread.
|
|
||||||
///
|
|
||||||
/// Note that screen reporting is enabled automatically and records the class name of the current
|
|
||||||
/// UIViewController for you without requiring you to call this method. The class name can
|
|
||||||
/// optionally be overridden by calling this method in the viewDidAppear callback of your
|
|
||||||
/// UIViewController and specifying the screenClassOverride parameter.
|
|
||||||
/// `setScreenName:screenClass:` must be called after `[super viewDidAppear:]`.
|
|
||||||
///
|
|
||||||
/// If your app does not use a distinct UIViewController for each screen, you should call this
|
|
||||||
/// method and specify a distinct screenName each time a new screen is presented to the user.
|
|
||||||
///
|
|
||||||
/// The screen name and screen class remain in effect until the current UIViewController changes or
|
|
||||||
/// a new call to setScreenName:screenClass: is made.
|
|
||||||
///
|
|
||||||
/// @warning If you override `viewDidAppear:` in your UIViewController but do not call
|
|
||||||
/// `[super viewDidAppear:]`, that screen class will not be tracked.
|
|
||||||
///
|
|
||||||
/// @param screenName The name of the current screen. Should contain 1 to 100 characters. Set to nil
|
|
||||||
/// to clear the current screen name.
|
|
||||||
/// @param screenClassOverride The name of the screen class. Should contain 1 to 100 characters. By
|
|
||||||
/// default this is the class name of the current UIViewController. Set to nil to revert to the
|
|
||||||
/// default class name.
|
|
||||||
+ (void)setScreenName:(nullable NSString *)screenName
|
|
||||||
screenClass:(nullable NSString *)screenClassOverride;
|
|
||||||
|
|
||||||
/// Sets whether analytics collection is enabled for this app on this device. This setting is
|
/// Sets whether analytics collection is enabled for this app on this device. This setting is
|
||||||
/// persisted across app sessions. By default it is enabled.
|
/// persisted across app sessions. By default it is enabled.
|
||||||
///
|
///
|
||||||
|
@ -125,13 +110,33 @@ NS_SWIFT_NAME(Analytics)
|
||||||
/// session terminates.
|
/// session terminates.
|
||||||
+ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval;
|
+ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval;
|
||||||
|
|
||||||
/// The unique ID for this instance of the application.
|
/// Returns the unique ID for this instance of the application or nil if
|
||||||
+ (NSString *)appInstanceID;
|
/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`.
|
||||||
|
///
|
||||||
|
/// @see `FIRAnalytics+Consent.h`
|
||||||
|
+ (nullable NSString *)appInstanceID;
|
||||||
|
|
||||||
/// Clears all analytics data for this instance from the device and resets the app instance ID.
|
/// Clears all analytics data for this instance from the device and resets the app instance ID.
|
||||||
/// FIRAnalyticsConfiguration values will be reset to the default values.
|
/// FIRAnalyticsConfiguration values will be reset to the default values.
|
||||||
+ (void)resetAnalyticsData;
|
+ (void)resetAnalyticsData;
|
||||||
|
|
||||||
|
/// Adds parameters that will be set on every event logged from the SDK, including automatic ones.
|
||||||
|
/// The values passed in the parameters dictionary will be added to the dictionary of default event
|
||||||
|
/// parameters. These parameters persist across app runs. They are of lower precedence than event
|
||||||
|
/// parameters, so if an event parameter and a parameter set using this API have the same name, the
|
||||||
|
/// value of the event parameter will be used. The same limitations on event parameters apply to
|
||||||
|
/// default event parameters.
|
||||||
|
///
|
||||||
|
/// @param parameters Parameters to be added to the dictionary of parameters added to every event.
|
||||||
|
/// They will be added to the dictionary of default event parameters, replacing any existing
|
||||||
|
/// parameter with the same name. Valid parameters are NSString and NSNumber (signed 64-bit
|
||||||
|
/// integer and 64-bit floating-point number). Setting a key's value to [NSNull null] will clear
|
||||||
|
/// that parameter. Passing in a nil dictionary will clear all parameters.
|
||||||
|
+ (void)setDefaultEventParameters:(nullable NSDictionary<NSString *, id> *)parameters;
|
||||||
|
|
||||||
|
/// Unavailable.
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
|
@ -52,6 +52,21 @@ static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart)
|
||||||
static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) =
|
static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) =
|
||||||
@"add_to_wishlist";
|
@"add_to_wishlist";
|
||||||
|
|
||||||
|
/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply
|
||||||
|
/// the @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency parameter
|
||||||
|
/// so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterAdPlatform (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdFormat (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdSource (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdUnitName (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) =
|
||||||
|
@"ad_impression";
|
||||||
|
|
||||||
/// App Open event. By logging this event when an App becomes active, developers can understand how
|
/// App Open event. By logging this event when an App becomes active, developers can understand how
|
||||||
/// often users leave and return during the course of a Session. Although Sessions are automatically
|
/// often users leave and return during the course of a Session. Although Sessions are automatically
|
||||||
/// reported, this event can provide further clarification around the continuous engagement of
|
/// reported, this event can provide further clarification around the continuous engagement of
|
||||||
|
@ -246,6 +261,15 @@ static NSString *const kFIREventPurchaseRefund NS_SWIFT_NAME(AnalyticsEventPurch
|
||||||
static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) =
|
static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) =
|
||||||
@"remove_from_cart";
|
@"remove_from_cart";
|
||||||
|
|
||||||
|
/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs.
|
||||||
|
/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterScreenClass (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterScreenName (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view";
|
||||||
|
|
||||||
/// Search event. Apps that support search features can use this event to contextualize search
|
/// Search event. Apps that support search features can use this event to contextualize search
|
||||||
/// operations by supplying the appropriate, corresponding parameters. This event can help you
|
/// operations by supplying the appropriate, corresponding parameters. This event can help you
|
||||||
/// identify the most popular content in your app. Params:
|
/// identify the most popular content in your app. Params:
|
|
@ -22,6 +22,17 @@
|
||||||
static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) =
|
static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) =
|
||||||
@"achievement_id";
|
@"achievement_id";
|
||||||
|
|
||||||
|
/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream).
|
||||||
|
/// (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdFormat : @"Banner",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) =
|
||||||
|
@"ad_format";
|
||||||
|
|
||||||
/// Ad Network Click ID (NSString). Used for network-specific click IDs which vary in format.
|
/// Ad Network Click ID (NSString). Used for network-specific click IDs which vary in format.
|
||||||
/// <pre>
|
/// <pre>
|
||||||
/// NSDictionary *params = @{
|
/// NSDictionary *params = @{
|
||||||
|
@ -32,6 +43,36 @@ static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParamet
|
||||||
static NSString *const kFIRParameterAdNetworkClickID
|
static NSString *const kFIRParameterAdNetworkClickID
|
||||||
NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid";
|
NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid";
|
||||||
|
|
||||||
|
/// The ad platform (e.g. MoPub, IronSource) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdPlatform : @"MoPub",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) =
|
||||||
|
@"ad_platform";
|
||||||
|
|
||||||
|
/// The ad source (e.g. AdColony) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdSource : @"AdColony",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) =
|
||||||
|
@"ad_source";
|
||||||
|
|
||||||
|
/// The ad unit name (e.g. Banner_03) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdUnitName : @"Banner_03",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) =
|
||||||
|
@"ad_unit_name";
|
||||||
|
|
||||||
/// A product affiliation to designate a supplying company or brick and mortar store location
|
/// A product affiliation to designate a supplying company or brick and mortar store location
|
||||||
/// (NSString). <pre>
|
/// (NSString). <pre>
|
||||||
/// NSDictionary *params = @{
|
/// NSDictionary *params = @{
|
||||||
|
@ -368,6 +409,26 @@ static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQua
|
||||||
/// </pre>
|
/// </pre>
|
||||||
static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score";
|
static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score";
|
||||||
|
|
||||||
|
/// Current screen class, such as the class name of the UIViewController, logged with screen_view
|
||||||
|
/// event and added to every event (NSString). <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterScreenClass : @"LoginViewController",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) =
|
||||||
|
@"screen_class";
|
||||||
|
|
||||||
|
/// Current screen name, such as the name of the UIViewController, logged with screen_view event and
|
||||||
|
/// added to every event (NSString). <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterScreenName : @"LoginView",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) =
|
||||||
|
@"screen_name";
|
||||||
|
|
||||||
/// The search string/keywords used (NSString).
|
/// The search string/keywords used (NSString).
|
||||||
/// <pre>
|
/// <pre>
|
||||||
/// NSDictionary *params = @{
|
/// NSDictionary *params = @{
|
|
@ -1,4 +1,5 @@
|
||||||
#import "FIRAnalytics+AppDelegate.h"
|
#import "FIRAnalytics+AppDelegate.h"
|
||||||
|
#import "FIRAnalytics+Consent.h"
|
||||||
#import "FIRAnalytics.h"
|
#import "FIRAnalytics.h"
|
||||||
#import "FIREventNames.h"
|
#import "FIREventNames.h"
|
||||||
#import "FIRParameterNames.h"
|
#import "FIRParameterNames.h"
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>FirebaseAnalytics</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.firebase.Firebase-FirebaseAnalytics</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>FirebaseAnalytics</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>8.0.0</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>iphonesimulator11.2</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -1,12 +1,13 @@
|
||||||
framework module FirebaseAnalytics {
|
framework module FirebaseAnalytics {
|
||||||
umbrella header "FirebaseAnalytics.h"
|
umbrella header "FirebaseAnalytics.h"
|
||||||
export *
|
export *
|
||||||
module * { export * }
|
module * { export * }
|
||||||
link "sqlite3"
|
link framework "CoreTelephony"
|
||||||
link "z"
|
link framework "Foundation"
|
||||||
link framework "CoreData"
|
|
||||||
link framework "Security"
|
link framework "Security"
|
||||||
link framework "StoreKit"
|
|
||||||
link framework "SystemConfiguration"
|
link framework "SystemConfiguration"
|
||||||
link framework "UIKit"
|
link framework "UIKit"
|
||||||
|
link "c++"
|
||||||
|
link "sqlite3"
|
||||||
|
link "z"
|
||||||
}
|
}
|
Binary file not shown.
|
@ -0,0 +1,62 @@
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "FIRAnalytics.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides App Delegate handlers to be used in your App Delegate.
|
||||||
|
*
|
||||||
|
* To save time integrating Firebase Analytics in an application, Firebase Analytics does not
|
||||||
|
* require delegation implementation from the AppDelegate. Instead this is automatically done by
|
||||||
|
* Firebase Analytics. Should you choose instead to delegate manually, you can turn off the App
|
||||||
|
* Delegate Proxy by adding FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting
|
||||||
|
* it to NO, and adding the methods in this category to corresponding delegation handlers.
|
||||||
|
*
|
||||||
|
* To handle Universal Links, you must return YES in
|
||||||
|
* [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
|
||||||
|
*/
|
||||||
|
@interface FIRAnalytics (AppDelegate)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles events related to a URL session that are waiting to be processed.
|
||||||
|
*
|
||||||
|
* For optimal use of Firebase Analytics, call this method from the
|
||||||
|
* [UIApplicationDelegate application:handleEventsForBackgroundURLSession:completionHandler]
|
||||||
|
* method of the app delegate in your app.
|
||||||
|
*
|
||||||
|
* @param identifier The identifier of the URL session requiring attention.
|
||||||
|
* @param completionHandler The completion handler to call when you finish processing the events.
|
||||||
|
* Calling this completion handler lets the system know that your app's user interface is
|
||||||
|
* updated and a new snapshot can be taken.
|
||||||
|
*/
|
||||||
|
+ (void)handleEventsForBackgroundURLSession:(NSString *)identifier
|
||||||
|
completionHandler:(nullable void (^)(void))completionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the event when the app is launched by a URL.
|
||||||
|
*
|
||||||
|
* Call this method from [UIApplicationDelegate application:openURL:options:] (on iOS 9.0 and
|
||||||
|
* above), or [UIApplicationDelegate application:openURL:sourceApplication:annotation:] (on
|
||||||
|
* iOS 8.x and below) in your app.
|
||||||
|
*
|
||||||
|
* @param url The URL resource to open. This resource can be a network resource or a file.
|
||||||
|
*/
|
||||||
|
+ (void)handleOpenURL:(NSURL *)url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the event when the app receives data associated with user activity that includes a
|
||||||
|
* Universal Link (on iOS 9.0 and above).
|
||||||
|
*
|
||||||
|
* Call this method from [UIApplication continueUserActivity:restorationHandler:] in your app
|
||||||
|
* delegate (on iOS 9.0 and above).
|
||||||
|
*
|
||||||
|
* @param userActivity The activity object containing the data associated with the task the user
|
||||||
|
* was performing.
|
||||||
|
*/
|
||||||
|
+ (void)handleUserActivity:(id)userActivity;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "FIRAnalytics.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and
|
||||||
|
/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status.
|
||||||
|
typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType);
|
||||||
|
extern FIRConsentType const FIRConsentTypeAdStorage;
|
||||||
|
extern FIRConsentType const FIRConsentTypeAnalyticsStorage;
|
||||||
|
|
||||||
|
/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and
|
||||||
|
/// `ConsentStatus.denied`.
|
||||||
|
typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus);
|
||||||
|
extern FIRConsentStatus const FIRConsentStatusDenied;
|
||||||
|
extern FIRConsentStatus const FIRConsentStatusGranted;
|
||||||
|
|
||||||
|
/// Sets the applicable end user consent state.
|
||||||
|
@interface FIRAnalytics (Consent)
|
||||||
|
|
||||||
|
/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this
|
||||||
|
/// device. Use the consent settings to specify individual consent type values. Settings are
|
||||||
|
/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`.
|
||||||
|
///
|
||||||
|
/// @param consentSettings An NSDictionary of consent types. Supported consent type keys are
|
||||||
|
/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are
|
||||||
|
/// `ConsentStatus.granted` and `ConsentStatus.denied`.
|
||||||
|
+ (void)setConsent:(NSDictionary<FIRConsentType, FIRConsentStatus> *)consentSettings;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,142 @@
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "FIREventNames.h"
|
||||||
|
#import "FIRParameterNames.h"
|
||||||
|
#import "FIRUserPropertyNames.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// The top level Firebase Analytics singleton that provides methods for logging events and setting
|
||||||
|
/// user properties. See <a href="http://goo.gl/gz8SLz">the developer guides</a> for general
|
||||||
|
/// information on using Firebase Analytics in your apps.
|
||||||
|
///
|
||||||
|
/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling
|
||||||
|
/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in
|
||||||
|
/// unexpected crashes at runtime.
|
||||||
|
NS_SWIFT_NAME(Analytics)
|
||||||
|
@interface FIRAnalytics : NSObject
|
||||||
|
|
||||||
|
/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have
|
||||||
|
/// the same parameters. Up to 500 event names are supported. Using predefined events and/or
|
||||||
|
/// parameters is recommended for optimal reporting.
|
||||||
|
///
|
||||||
|
/// The following event names are reserved and cannot be used:
|
||||||
|
/// <ul>
|
||||||
|
/// <li>ad_activeview</li>
|
||||||
|
/// <li>ad_click</li>
|
||||||
|
/// <li>ad_exposure</li>
|
||||||
|
/// <li>ad_query</li>
|
||||||
|
/// <li>ad_reward</li>
|
||||||
|
/// <li>adunit_exposure</li>
|
||||||
|
/// <li>app_background</li>
|
||||||
|
/// <li>app_clear_data</li>
|
||||||
|
/// <li>app_exception</li>
|
||||||
|
/// <li>app_remove</li>
|
||||||
|
/// <li>app_store_refund</li>
|
||||||
|
/// <li>app_store_subscription_cancel</li>
|
||||||
|
/// <li>app_store_subscription_convert</li>
|
||||||
|
/// <li>app_store_subscription_renew</li>
|
||||||
|
/// <li>app_update</li>
|
||||||
|
/// <li>app_upgrade</li>
|
||||||
|
/// <li>dynamic_link_app_open</li>
|
||||||
|
/// <li>dynamic_link_app_update</li>
|
||||||
|
/// <li>dynamic_link_first_open</li>
|
||||||
|
/// <li>error</li>
|
||||||
|
/// <li>firebase_campaign</li>
|
||||||
|
/// <li>first_open</li>
|
||||||
|
/// <li>first_visit</li>
|
||||||
|
/// <li>in_app_purchase</li>
|
||||||
|
/// <li>notification_dismiss</li>
|
||||||
|
/// <li>notification_foreground</li>
|
||||||
|
/// <li>notification_open</li>
|
||||||
|
/// <li>notification_receive</li>
|
||||||
|
/// <li>os_update</li>
|
||||||
|
/// <li>session_start</li>
|
||||||
|
/// <li>session_start_with_rollout</li>
|
||||||
|
/// <li>user_engagement</li>
|
||||||
|
/// </ul>
|
||||||
|
///
|
||||||
|
/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or
|
||||||
|
/// underscores. The name must start with an alphabetic character. Some event names are
|
||||||
|
/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_",
|
||||||
|
/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are
|
||||||
|
/// case-sensitive and that logging two events whose names differ only in case will result in
|
||||||
|
/// two distinct events. To manually log screen view events, use the `screen_view` event name.
|
||||||
|
/// @param parameters The dictionary of event parameters. Passing nil indicates that the event has
|
||||||
|
/// no parameters. Parameter names can be up to 40 characters long and must start with an
|
||||||
|
/// alphabetic character and contain only alphanumeric characters and underscores. Only NSString
|
||||||
|
/// and NSNumber (signed 64-bit integer and 64-bit floating-point number) parameter types are
|
||||||
|
/// supported. NSString parameter values can be up to 100 characters long. The "firebase_",
|
||||||
|
/// "google_", and "ga_" prefixes are reserved and should not be used for parameter names.
|
||||||
|
+ (void)logEventWithName:(NSString *)name
|
||||||
|
parameters:(nullable NSDictionary<NSString *, id> *)parameters
|
||||||
|
NS_SWIFT_NAME(logEvent(_:parameters:));
|
||||||
|
|
||||||
|
/// Sets a user property to a given value. Up to 25 user property names are supported. Once set,
|
||||||
|
/// user property values persist throughout the app lifecycle and across sessions.
|
||||||
|
///
|
||||||
|
/// The following user property names are reserved and cannot be used:
|
||||||
|
/// <ul>
|
||||||
|
/// <li>first_open_time</li>
|
||||||
|
/// <li>last_deep_link_referrer</li>
|
||||||
|
/// <li>user_id</li>
|
||||||
|
/// </ul>
|
||||||
|
///
|
||||||
|
/// @param value The value of the user property. Values can be up to 36 characters long. Setting the
|
||||||
|
/// value to nil removes the user property.
|
||||||
|
/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters
|
||||||
|
/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and
|
||||||
|
/// "ga_" prefixes are reserved and should not be used for user property names.
|
||||||
|
+ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name
|
||||||
|
NS_SWIFT_NAME(setUserProperty(_:forName:));
|
||||||
|
|
||||||
|
/// Sets the user ID property. This feature must be used in accordance with
|
||||||
|
/// <a href="https://www.google.com/policies/privacy">Google's Privacy Policy</a>
|
||||||
|
///
|
||||||
|
/// @param userID The user ID to ascribe to the user of this app on this device, which must be
|
||||||
|
/// non-empty and no more than 256 characters long. Setting userID to nil removes the user ID.
|
||||||
|
+ (void)setUserID:(nullable NSString *)userID;
|
||||||
|
|
||||||
|
/// Sets whether analytics collection is enabled for this app on this device. This setting is
|
||||||
|
/// persisted across app sessions. By default it is enabled.
|
||||||
|
///
|
||||||
|
/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection.
|
||||||
|
+ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled;
|
||||||
|
|
||||||
|
/// Sets the interval of inactivity in seconds that terminates the current session. The default
|
||||||
|
/// value is 1800 seconds (30 minutes).
|
||||||
|
///
|
||||||
|
/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current
|
||||||
|
/// session terminates.
|
||||||
|
+ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval;
|
||||||
|
|
||||||
|
/// Returns the unique ID for this instance of the application or nil if
|
||||||
|
/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`.
|
||||||
|
///
|
||||||
|
/// @see `FIRAnalytics+Consent.h`
|
||||||
|
+ (nullable NSString *)appInstanceID;
|
||||||
|
|
||||||
|
/// Clears all analytics data for this instance from the device and resets the app instance ID.
|
||||||
|
/// FIRAnalyticsConfiguration values will be reset to the default values.
|
||||||
|
+ (void)resetAnalyticsData;
|
||||||
|
|
||||||
|
/// Adds parameters that will be set on every event logged from the SDK, including automatic ones.
|
||||||
|
/// The values passed in the parameters dictionary will be added to the dictionary of default event
|
||||||
|
/// parameters. These parameters persist across app runs. They are of lower precedence than event
|
||||||
|
/// parameters, so if an event parameter and a parameter set using this API have the same name, the
|
||||||
|
/// value of the event parameter will be used. The same limitations on event parameters apply to
|
||||||
|
/// default event parameters.
|
||||||
|
///
|
||||||
|
/// @param parameters Parameters to be added to the dictionary of parameters added to every event.
|
||||||
|
/// They will be added to the dictionary of default event parameters, replacing any existing
|
||||||
|
/// parameter with the same name. Valid parameters are NSString and NSNumber (signed 64-bit
|
||||||
|
/// integer and 64-bit floating-point number). Setting a key's value to [NSNull null] will clear
|
||||||
|
/// that parameter. Passing in a nil dictionary will clear all parameters.
|
||||||
|
+ (void)setDefaultEventParameters:(nullable NSDictionary<NSString *, id> *)parameters;
|
||||||
|
|
||||||
|
/// Unavailable.
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,495 @@
|
||||||
|
/// @file FIREventNames.h
|
||||||
|
///
|
||||||
|
/// Predefined event names.
|
||||||
|
///
|
||||||
|
/// An Event is an important occurrence in your app that you want to measure. You can report up to
|
||||||
|
/// 500 different types of Events per app and you can associate up to 25 unique parameters with each
|
||||||
|
/// Event type. Some common events are suggested below, but you may also choose to specify custom
|
||||||
|
/// Event types that are associated with your specific app. Each event type is identified by a
|
||||||
|
/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric
|
||||||
|
/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_",
|
||||||
|
/// "google_", and "ga_" prefixes are reserved and should not be used.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/// Add Payment Info event. This event signifies that a user has submitted their payment
|
||||||
|
/// information. Note: If you supply the @c kFIRParameterValue parameter, you must also supply the
|
||||||
|
/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCoupon (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterPaymentType (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) =
|
||||||
|
@"add_payment_info";
|
||||||
|
|
||||||
|
/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for
|
||||||
|
/// purchase. Add this event to a funnel with @c kFIREventPurchase to gauge the effectiveness of
|
||||||
|
/// your checkout process. Note: If you supply the @c kFIRParameterValue parameter, you must also
|
||||||
|
/// supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed
|
||||||
|
/// accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart";
|
||||||
|
|
||||||
|
/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use
|
||||||
|
/// this event to identify popular gift items. Note: If you supply the @c kFIRParameterValue
|
||||||
|
/// parameter, you must also supply the @c kFIRParameterCurrency parameter so that revenue metrics
|
||||||
|
/// can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) =
|
||||||
|
@"add_to_wishlist";
|
||||||
|
|
||||||
|
/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply
|
||||||
|
/// the @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency parameter
|
||||||
|
/// so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterAdPlatform (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdFormat (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdSource (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdUnitName (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) =
|
||||||
|
@"ad_impression";
|
||||||
|
|
||||||
|
/// App Open event. By logging this event when an App becomes active, developers can understand how
|
||||||
|
/// often users leave and return during the course of a Session. Although Sessions are automatically
|
||||||
|
/// reported, this event can provide further clarification around the continuous engagement of
|
||||||
|
/// app-users.
|
||||||
|
static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open";
|
||||||
|
|
||||||
|
/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of
|
||||||
|
/// checking out. Add this event to a funnel with your @c kFIREventPurchase event to gauge the
|
||||||
|
/// effectiveness of your checkout process. Note: If you supply the @c kFIRParameterValue parameter,
|
||||||
|
/// you must also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be
|
||||||
|
/// computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCoupon (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) =
|
||||||
|
@"begin_checkout";
|
||||||
|
|
||||||
|
/// Campaign Detail event. Log this event to supply the referral details of a re-engagement
|
||||||
|
/// campaign. Note: you must supply at least one of the required parameters kFIRParameterSource,
|
||||||
|
/// kFIRParameterMedium or kFIRParameterCampaign. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterSource (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterMedium (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterCampaign (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterTerm (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterContent (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterAdNetworkClickID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCP1 (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) =
|
||||||
|
@"campaign_details";
|
||||||
|
|
||||||
|
/// Checkout progress. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCheckoutStep (unsigned 64-bit integer as NSNumber)</li>
|
||||||
|
/// <li>@c kFIRParameterCheckoutOption (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
/// <b>This constant has been deprecated.</b>
|
||||||
|
static NSString *const kFIREventCheckoutProgress NS_SWIFT_NAME(AnalyticsEventCheckoutProgress) =
|
||||||
|
@"checkout_progress";
|
||||||
|
|
||||||
|
/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log
|
||||||
|
/// this along with @c kFIREventSpendVirtualCurrency to better understand your virtual economy.
|
||||||
|
/// Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterVirtualCurrencyName (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (signed 64-bit integer or double as NSNumber)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventEarnVirtualCurrency
|
||||||
|
NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency";
|
||||||
|
|
||||||
|
/// E-Commerce Purchase event. This event signifies that an item was purchased by a user. Note:
|
||||||
|
/// This is different from the in-app purchase event, which is reported automatically for App
|
||||||
|
/// Store-based apps. Note: If you supply the @c kFIRParameterValue parameter, you must also
|
||||||
|
/// supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed
|
||||||
|
/// accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTransactionID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTax (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterShipping (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCoupon (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterLocation (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterStartDate (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterEndDate (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for
|
||||||
|
/// hotel bookings</li>
|
||||||
|
/// <li>@c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for
|
||||||
|
/// hotel bookings</li>
|
||||||
|
/// <li>@c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional)
|
||||||
|
/// for travel bookings</li>
|
||||||
|
/// <li>@c kFIRParameterOrigin (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterDestination (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTravelClass (NSString) (optional) for travel bookings</li>
|
||||||
|
/// </ul>
|
||||||
|
/// <b>This constant has been deprecated. Use @c kFIREventPurchase constant instead.</b>
|
||||||
|
static NSString *const kFIREventEcommercePurchase NS_SWIFT_NAME(AnalyticsEventEcommercePurchase) =
|
||||||
|
@"ecommerce_purchase";
|
||||||
|
|
||||||
|
/// Generate Lead event. Log this event when a lead has been generated in the app to understand the
|
||||||
|
/// efficacy of your install and re-engagement campaigns. Note: If you supply the
|
||||||
|
/// @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency
|
||||||
|
/// parameter so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) =
|
||||||
|
@"generate_lead";
|
||||||
|
|
||||||
|
/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use
|
||||||
|
/// this event to analyze how popular certain groups or social features are in your app. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterGroupID (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group";
|
||||||
|
|
||||||
|
/// Level End event. Log this event when the user finishes a level. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterLevelName (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterSuccess (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end";
|
||||||
|
|
||||||
|
/// Level Start event. Log this event when the user starts a new level. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterLevelName (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start";
|
||||||
|
|
||||||
|
/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can
|
||||||
|
/// help you gauge the level distribution of your userbase and help you identify certain levels that
|
||||||
|
/// are difficult to pass. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterLevel (signed 64-bit integer as NSNumber)</li>
|
||||||
|
/// <li>@c kFIRParameterCharacter (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up";
|
||||||
|
|
||||||
|
/// Login event. Apps with a login feature can report this event to signify that a user has logged
|
||||||
|
/// in.
|
||||||
|
static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login";
|
||||||
|
|
||||||
|
/// Post Score event. Log this event when the user posts a score in your gaming app. This event can
|
||||||
|
/// help you understand how users are actually performing in your game and it can help you correlate
|
||||||
|
/// high scores with certain audiences or behaviors. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterScore (signed 64-bit integer as NSNumber)</li>
|
||||||
|
/// <li>@c kFIRParameterLevel (signed 64-bit integer as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCharacter (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score";
|
||||||
|
|
||||||
|
/// Present Offer event. This event signifies that the app has presented a purchase offer to a user.
|
||||||
|
/// Add this event to a funnel with the kFIREventAddToCart and kFIREventEcommercePurchase to gauge
|
||||||
|
/// your conversion process. Note: If you supply the @c kFIRParameterValue parameter, you must
|
||||||
|
/// also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed
|
||||||
|
/// accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterQuantity (signed 64-bit integer as NSNumber)</li>
|
||||||
|
/// <li>@c kFIRParameterItemID (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterItemName (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterItemCategory (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterItemLocationID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterPrice (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
/// <b>This constant has been deprecated. Use @c kFIREventViewPromotion constant instead.</b>
|
||||||
|
static NSString *const kFIREventPresentOffer NS_SWIFT_NAME(AnalyticsEventPresentOffer) =
|
||||||
|
@"present_offer";
|
||||||
|
|
||||||
|
/// E-Commerce Purchase Refund event. This event signifies that an item purchase was refunded.
|
||||||
|
/// Note: If you supply the @c kFIRParameterValue parameter, you must also supply the
|
||||||
|
/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately.
|
||||||
|
/// Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTransactionID (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
/// <b>This constant has been deprecated. Use @c kFIREventRefund constant instead.</b>
|
||||||
|
static NSString *const kFIREventPurchaseRefund NS_SWIFT_NAME(AnalyticsEventPurchaseRefund) =
|
||||||
|
@"purchase_refund";
|
||||||
|
|
||||||
|
/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart.
|
||||||
|
/// Note: If you supply the @c kFIRParameterValue parameter, you must also supply the @c
|
||||||
|
/// kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) =
|
||||||
|
@"remove_from_cart";
|
||||||
|
|
||||||
|
/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs.
|
||||||
|
/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterScreenClass (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterScreenName (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view";
|
||||||
|
|
||||||
|
/// Search event. Apps that support search features can use this event to contextualize search
|
||||||
|
/// operations by supplying the appropriate, corresponding parameters. This event can help you
|
||||||
|
/// identify the most popular content in your app. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterSearchTerm (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterStartDate (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterEndDate (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterNumberOfNights (signed 64-bit integer as NSNumber) (optional) for
|
||||||
|
/// hotel bookings</li>
|
||||||
|
/// <li>@c kFIRParameterNumberOfRooms (signed 64-bit integer as NSNumber) (optional) for
|
||||||
|
/// hotel bookings</li>
|
||||||
|
/// <li>@c kFIRParameterNumberOfPassengers (signed 64-bit integer as NSNumber) (optional)
|
||||||
|
/// for travel bookings</li>
|
||||||
|
/// <li>@c kFIRParameterOrigin (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterDestination (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTravelClass (NSString) (optional) for travel bookings</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search";
|
||||||
|
|
||||||
|
/// Select Content event. This general purpose event signifies that a user has selected some content
|
||||||
|
/// of a certain type in an app. The content can be any object in your app. This event can help you
|
||||||
|
/// identify popular content and categories of content in your app. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterContentType (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterItemID (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) =
|
||||||
|
@"select_content";
|
||||||
|
|
||||||
|
/// Set checkout option. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCheckoutStep (unsigned 64-bit integer as NSNumber)</li>
|
||||||
|
/// <li>@c kFIRParameterCheckoutOption (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
/// <b>This constant has been deprecated.</b>
|
||||||
|
static NSString *const kFIREventSetCheckoutOption NS_SWIFT_NAME(AnalyticsEventSetCheckoutOption) =
|
||||||
|
@"set_checkout_option";
|
||||||
|
|
||||||
|
/// Share event. Apps with social features can log the Share event to identify the most viral
|
||||||
|
/// content. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterContentType (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterItemID (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share";
|
||||||
|
|
||||||
|
/// Sign Up event. This event indicates that a user has signed up for an account in your app. The
|
||||||
|
/// parameter signifies the method by which the user signed up. Use this event to understand the
|
||||||
|
/// different behaviors between logged in and logged out users. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterSignUpMethod (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up";
|
||||||
|
|
||||||
|
/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can
|
||||||
|
/// help you identify which virtual goods are the most popular objects of purchase. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterItemName (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterVirtualCurrencyName (NSString)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (signed 64-bit integer or double as NSNumber)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventSpendVirtualCurrency
|
||||||
|
NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency";
|
||||||
|
|
||||||
|
/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use
|
||||||
|
/// this in a funnel with kFIREventTutorialComplete to understand how many users complete this
|
||||||
|
/// process and move on to the full app experience.
|
||||||
|
static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) =
|
||||||
|
@"tutorial_begin";
|
||||||
|
|
||||||
|
/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding
|
||||||
|
/// process. Add this to a funnel with kFIREventTutorialBegin to gauge the completion rate of your
|
||||||
|
/// on-boarding process.
|
||||||
|
static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) =
|
||||||
|
@"tutorial_complete";
|
||||||
|
|
||||||
|
/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your
|
||||||
|
/// game. Since achievements generally represent the breadth of a gaming experience, this event can
|
||||||
|
/// help you understand how many users are experiencing all that your game has to offer. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterAchievementID (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) =
|
||||||
|
@"unlock_achievement";
|
||||||
|
|
||||||
|
/// View Item event. This event signifies that a user has viewed an item. Use the appropriate
|
||||||
|
/// parameters to contextualize the event. Use this event to discover the most popular items viewed
|
||||||
|
/// in your app. Note: If you supply the @c kFIRParameterValue parameter, you must also supply the
|
||||||
|
/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item";
|
||||||
|
|
||||||
|
/// View Item List event. Log this event when a user sees a list of items or offerings. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItemListID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItemListName (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) =
|
||||||
|
@"view_item_list";
|
||||||
|
|
||||||
|
/// View Search Results event. Log this event when the user has been presented with the results of a
|
||||||
|
/// search. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterSearchTerm (NSString)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) =
|
||||||
|
@"view_search_results";
|
||||||
|
|
||||||
|
/// Add Shipping Info event. This event signifies that a user has submitted their shipping
|
||||||
|
/// information. Note: If you supply the @c kFIRParameterValue parameter, you must also supply the
|
||||||
|
/// @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCoupon (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterShippingTier (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) =
|
||||||
|
@"add_shipping_info";
|
||||||
|
|
||||||
|
/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note:
|
||||||
|
/// This is different from the in-app purchase event, which is reported automatically for App
|
||||||
|
/// Store-based apps. Note: If you supply the @c kFIRParameterValue parameter, you must also supply
|
||||||
|
/// the @c kFIRParameterCurrency parameter so that revenue metrics can be computed accurately.
|
||||||
|
/// Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterAffiliation (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCoupon (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterShipping (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTax (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTransactionID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase";
|
||||||
|
|
||||||
|
/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the
|
||||||
|
/// @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency parameter so
|
||||||
|
/// that revenue metrics can be computed accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterAffiliation (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCoupon (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterShipping (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTax (double as NSNumber) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterTransactionID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund";
|
||||||
|
|
||||||
|
/// Select Item event. This event signifies that an item was selected by a user from a list. Use the
|
||||||
|
/// appropriate parameters to contextualize the event. Use this event to discover the most popular
|
||||||
|
/// items selected. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItemListID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItemListName (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item";
|
||||||
|
|
||||||
|
/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the
|
||||||
|
/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion
|
||||||
|
/// applies. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCreativeName (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCreativeSlot (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterLocationID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterPromotionID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterPromotionName (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) =
|
||||||
|
@"select_promotion";
|
||||||
|
|
||||||
|
/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to
|
||||||
|
/// analyze your purchase funnel. Note: If you supply the @c kFIRParameterValue parameter, you must
|
||||||
|
/// also supply the @c kFIRParameterCurrency parameter so that revenue metrics can be computed
|
||||||
|
/// accurately. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCurrency (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterValue (double as NSNumber) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart";
|
||||||
|
|
||||||
|
/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event
|
||||||
|
/// to a funnel with the @c kFIREventAddToCart and @c kFIREventPurchase to gauge your conversion
|
||||||
|
/// process. Params:
|
||||||
|
///
|
||||||
|
/// <ul>
|
||||||
|
/// <li>@c kFIRParameterCreativeName (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterCreativeSlot (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterItems (NSArray) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterLocationID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterPromotionID (NSString) (optional)</li>
|
||||||
|
/// <li>@c kFIRParameterPromotionName (NSString) (optional)</li>
|
||||||
|
/// </ul>
|
||||||
|
static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) =
|
||||||
|
@"view_promotion";
|
|
@ -0,0 +1,731 @@
|
||||||
|
/// @file FIRParameterNames.h
|
||||||
|
///
|
||||||
|
/// Predefined event parameter names.
|
||||||
|
///
|
||||||
|
/// Params supply information that contextualize Events. You can associate up to 25 unique Params
|
||||||
|
/// with each Event type. Some Params are suggested below for certain common Events, but you are
|
||||||
|
/// not limited to these. You may supply extra Params for suggested Events or custom Params for
|
||||||
|
/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric
|
||||||
|
/// characters and underscores ("_"), and must start with an alphabetic character. Param values can
|
||||||
|
/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and
|
||||||
|
/// should not be used.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/// Game achievement ID (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAchievementID : @"10_matches_won",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) =
|
||||||
|
@"achievement_id";
|
||||||
|
|
||||||
|
/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream).
|
||||||
|
/// (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdFormat : @"Banner",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) =
|
||||||
|
@"ad_format";
|
||||||
|
|
||||||
|
/// Ad Network Click ID (NSString). Used for network-specific click IDs which vary in format.
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdNetworkClickID : @"1234567",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdNetworkClickID
|
||||||
|
NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid";
|
||||||
|
|
||||||
|
/// The ad platform (e.g. MoPub, IronSource) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdPlatform : @"MoPub",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) =
|
||||||
|
@"ad_platform";
|
||||||
|
|
||||||
|
/// The ad source (e.g. AdColony) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdSource : @"AdColony",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) =
|
||||||
|
@"ad_source";
|
||||||
|
|
||||||
|
/// The ad unit name (e.g. Banner_03) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAdUnitName : @"Banner_03",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) =
|
||||||
|
@"ad_unit_name";
|
||||||
|
|
||||||
|
/// A product affiliation to designate a supplying company or brick and mortar store location
|
||||||
|
/// (NSString). <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterAffiliation : @"Google Store",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) =
|
||||||
|
@"affiliation";
|
||||||
|
|
||||||
|
/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to
|
||||||
|
/// capture campaign information, otherwise can be populated by developer. Highly Recommended
|
||||||
|
/// (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCampaign : @"winter_promotion",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) =
|
||||||
|
@"campaign";
|
||||||
|
|
||||||
|
/// Character used in game (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCharacter : @"beat_boss",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) =
|
||||||
|
@"character";
|
||||||
|
|
||||||
|
/// The checkout step (1..N) (unsigned 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCheckoutStep : @"1",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
/// <b>This constant has been deprecated.</b>
|
||||||
|
static NSString *const kFIRParameterCheckoutStep NS_SWIFT_NAME(AnalyticsParameterCheckoutStep) =
|
||||||
|
@"checkout_step";
|
||||||
|
|
||||||
|
/// Some option on a step in an ecommerce flow (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCheckoutOption : @"Visa",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
/// <b>This constant has been deprecated.</b>
|
||||||
|
static NSString *const kFIRParameterCheckoutOption
|
||||||
|
NS_SWIFT_NAME(AnalyticsParameterCheckoutOption) = @"checkout_option";
|
||||||
|
|
||||||
|
/// Campaign content (NSString).
|
||||||
|
static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content";
|
||||||
|
|
||||||
|
/// Type of content selected (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterContentType : @"news article",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) =
|
||||||
|
@"content_type";
|
||||||
|
|
||||||
|
/// Coupon code used for a purchase (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCoupon : @"SUMMER_FUN",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon";
|
||||||
|
|
||||||
|
/// Campaign custom parameter (NSString). Used as a method of capturing custom data in a campaign.
|
||||||
|
/// Use varies by network.
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCP1 : @"custom_data",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1";
|
||||||
|
|
||||||
|
/// The name of a creative used in a promotional spot (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCreativeName : @"Summer Sale",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) =
|
||||||
|
@"creative_name";
|
||||||
|
|
||||||
|
/// The name of a creative slot (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCreativeSlot : @"summer_banner2",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) =
|
||||||
|
@"creative_slot";
|
||||||
|
|
||||||
|
/// Currency of the purchase or items associated with the event, in 3-letter
|
||||||
|
/// <a href="http://en.wikipedia.org/wiki/ISO_4217#Active_codes"> ISO_4217</a> format (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterCurrency : @"USD",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) =
|
||||||
|
@"currency";
|
||||||
|
|
||||||
|
/// Flight or Travel destination (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterDestination : @"Mountain View, CA",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) =
|
||||||
|
@"destination";
|
||||||
|
|
||||||
|
/// The arrival date, check-out date or rental end date for the item. This should be in
|
||||||
|
/// YYYY-MM-DD format (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterEndDate : @"2015-09-14",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date";
|
||||||
|
|
||||||
|
/// Flight number for travel events (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterFlightNumber : @"ZZ800",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) =
|
||||||
|
@"flight_number";
|
||||||
|
|
||||||
|
/// Group/clan/guild ID (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterGroupID : @"g1",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id";
|
||||||
|
|
||||||
|
/// The index of the item in a list (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterIndex : @(5),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index";
|
||||||
|
|
||||||
|
/// Item brand (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemBrand : @"Google",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) =
|
||||||
|
@"item_brand";
|
||||||
|
|
||||||
|
/// Item category (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemCategory : @"pants",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) =
|
||||||
|
@"item_category";
|
||||||
|
|
||||||
|
/// Item ID (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemID : @"SKU_12345",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id";
|
||||||
|
|
||||||
|
/// The Google <a href="https://developers.google.com/places/place-id">Place ID</a> (NSString) that
|
||||||
|
/// corresponds to the associated item. Alternatively, you can supply your own custom Location ID.
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemLocationID : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
/// <b>This constant has been deprecated. Use @c kFIRParameterLocationID constant instead.</b>
|
||||||
|
static NSString *const kFIRParameterItemLocationID
|
||||||
|
NS_SWIFT_NAME(AnalyticsParameterItemLocationID) = @"item_location_id";
|
||||||
|
|
||||||
|
/// Item Name (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemName : @"jeggings",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) =
|
||||||
|
@"item_name";
|
||||||
|
|
||||||
|
/// The list in which the item was presented to the user (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemList : @"Search Results",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
/// <b>This constant has been deprecated. Use @c kFIRParameterItemListName constant instead.</b>
|
||||||
|
static NSString *const kFIRParameterItemList NS_SWIFT_NAME(AnalyticsParameterItemList) =
|
||||||
|
@"item_list";
|
||||||
|
|
||||||
|
/// Item variant (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemVariant : @"Black",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) =
|
||||||
|
@"item_variant";
|
||||||
|
|
||||||
|
/// Level in game (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterLevel : @(42),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level";
|
||||||
|
|
||||||
|
/// Location (NSString). The Google <a href="https://developers.google.com/places/place-id">Place ID
|
||||||
|
/// </a> that corresponds to the associated event. Alternatively, you can supply your own custom
|
||||||
|
/// Location ID.
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterLocation : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) =
|
||||||
|
@"location";
|
||||||
|
|
||||||
|
/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended
|
||||||
|
/// (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterMedium : @"email",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium";
|
||||||
|
|
||||||
|
/// Number of nights staying at hotel (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterNumberOfNights : @(3),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterNumberOfNights
|
||||||
|
NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights";
|
||||||
|
|
||||||
|
/// Number of passengers traveling (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterNumberOfPassengers : @(11),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterNumberOfPassengers
|
||||||
|
NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers";
|
||||||
|
|
||||||
|
/// Number of rooms for travel events (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterNumberOfRooms : @(2),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) =
|
||||||
|
@"number_of_rooms";
|
||||||
|
|
||||||
|
/// Flight or Travel origin (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterOrigin : @"Mountain View, CA",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin";
|
||||||
|
|
||||||
|
/// Purchase price (double as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterPrice : @(1.0),
|
||||||
|
/// kFIRParameterCurrency : @"USD", // e.g. $1.00 USD
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price";
|
||||||
|
|
||||||
|
/// Purchase quantity (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterQuantity : @(1),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) =
|
||||||
|
@"quantity";
|
||||||
|
|
||||||
|
/// Score in game (signed 64-bit integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterScore : @(4200),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score";
|
||||||
|
|
||||||
|
/// Current screen class, such as the class name of the UIViewController, logged with screen_view
|
||||||
|
/// event and added to every event (NSString). <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterScreenClass : @"LoginViewController",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) =
|
||||||
|
@"screen_class";
|
||||||
|
|
||||||
|
/// Current screen name, such as the name of the UIViewController, logged with screen_view event and
|
||||||
|
/// added to every event (NSString). <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterScreenName : @"LoginView",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) =
|
||||||
|
@"screen_name";
|
||||||
|
|
||||||
|
/// The search string/keywords used (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterSearchTerm : @"periodic table",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) =
|
||||||
|
@"search_term";
|
||||||
|
|
||||||
|
/// Shipping cost associated with a transaction (double as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterShipping : @(5.99),
|
||||||
|
/// kFIRParameterCurrency : @"USD", // e.g. $5.99 USD
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) =
|
||||||
|
@"shipping";
|
||||||
|
|
||||||
|
/// Sign up method (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterSignUpMethod : @"google",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
///
|
||||||
|
/// <b>This constant has been deprecated. Use Method constant instead.</b>
|
||||||
|
static NSString *const kFIRParameterSignUpMethod NS_SWIFT_NAME(AnalyticsParameterSignUpMethod) =
|
||||||
|
@"sign_up_method";
|
||||||
|
|
||||||
|
/// A particular approach used in an operation; for example, "facebook" or "email" in the context
|
||||||
|
/// of a sign_up or login event. (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterMethod : @"google",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method";
|
||||||
|
|
||||||
|
/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban
|
||||||
|
/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your
|
||||||
|
/// property. Highly recommended (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterSource : @"InMobi",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source";
|
||||||
|
|
||||||
|
/// The departure date, check-in date or rental start date for the item. This should be in
|
||||||
|
/// YYYY-MM-DD format (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterStartDate : @"2015-09-14",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) =
|
||||||
|
@"start_date";
|
||||||
|
|
||||||
|
/// Tax cost associated with a transaction (double as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterTax : @(2.43),
|
||||||
|
/// kFIRParameterCurrency : @"USD", // e.g. $2.43 USD
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax";
|
||||||
|
|
||||||
|
/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword
|
||||||
|
/// (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterTerm : @"game",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term";
|
||||||
|
|
||||||
|
/// The unique identifier of a transaction (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterTransactionID : @"T12345",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) =
|
||||||
|
@"transaction_id";
|
||||||
|
|
||||||
|
/// Travel class (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterTravelClass : @"business",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) =
|
||||||
|
@"travel_class";
|
||||||
|
|
||||||
|
/// A context-specific numeric value which is accumulated automatically for each event type. This is
|
||||||
|
/// a general purpose parameter that is useful for accumulating a key metric that pertains to an
|
||||||
|
/// event. Examples include revenue, distance, time and points. Value should be specified as signed
|
||||||
|
/// 64-bit integer or double as NSNumber. Notes: Values for pre-defined currency-related events
|
||||||
|
/// (such as @c kFIREventAddToCart) should be supplied using double as NSNumber and must be
|
||||||
|
/// accompanied by a @c kFIRParameterCurrency parameter. The valid range of accumulated values is
|
||||||
|
/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the
|
||||||
|
/// corresponding @c kFIRParameterCurrency parameter, or supplying an invalid
|
||||||
|
/// <a href="https://goo.gl/qqX3J2">currency code</a> for conversion events will cause that
|
||||||
|
/// conversion to be omitted from reporting.
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterValue : @(3.99),
|
||||||
|
/// kFIRParameterCurrency : @"USD", // e.g. $3.99 USD
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value";
|
||||||
|
|
||||||
|
/// Name of virtual currency type (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterVirtualCurrencyName : @"virtual_currency_name",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterVirtualCurrencyName
|
||||||
|
NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name";
|
||||||
|
|
||||||
|
/// The name of a level in a game (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterLevelName : @"room_1",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) =
|
||||||
|
@"level_name";
|
||||||
|
|
||||||
|
/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (unsigned
|
||||||
|
/// integer as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterSuccess : @(1),
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success";
|
||||||
|
|
||||||
|
/// Indicates that the associated event should either extend the current session
|
||||||
|
/// or start a new session if no session was active when the event was logged.
|
||||||
|
/// Specify YES to extend the current session or to start a new session; any
|
||||||
|
/// other value will not extend or start a session.
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterExtendSession : @YES,
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) =
|
||||||
|
@"extend_session";
|
||||||
|
|
||||||
|
/// Monetary value of discount associated with a purchase (double as NSNumber).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterDiscount : @(2.0),
|
||||||
|
/// kFIRParameterCurrency : @"USD", // e.g. $2.00 USD
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) =
|
||||||
|
@"discount";
|
||||||
|
|
||||||
|
/// Item Category (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemCategory2 : @"pants",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) =
|
||||||
|
@"item_category2";
|
||||||
|
|
||||||
|
/// Item Category (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemCategory3 : @"pants",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) =
|
||||||
|
@"item_category3";
|
||||||
|
|
||||||
|
/// Item Category (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemCategory4 : @"pants",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) =
|
||||||
|
@"item_category4";
|
||||||
|
|
||||||
|
/// Item Category (context-specific) (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemCategory5 : @"pants",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) =
|
||||||
|
@"item_category5";
|
||||||
|
|
||||||
|
/// The ID of the list in which the item was presented to the user (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemListID : @"ABC123",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) =
|
||||||
|
@"item_list_id";
|
||||||
|
|
||||||
|
/// The name of the list in which the item was presented to the user (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItemListName : @"Related products",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) =
|
||||||
|
@"item_list_name";
|
||||||
|
|
||||||
|
/// The list of items involved in the transaction. (NSArray).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterItems : @[
|
||||||
|
/// @{kFIRParameterItemName : @"jeggings", kFIRParameterItemCategory : @"pants"},
|
||||||
|
/// @{kFIRParameterItemName : @"boots", kFIRParameterItemCategory : @"shoes"},
|
||||||
|
/// ],
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items";
|
||||||
|
|
||||||
|
/// The location associated with the event. Preferred to be the Google
|
||||||
|
/// <a href="https://developers.google.com/places/place-id">Place ID</a> that corresponds to the
|
||||||
|
/// associated item but could be overridden to a custom location ID string.(NSString). <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterLocationID : @"ChIJiyj437sx3YAR9kUWC8QkLzQ",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) =
|
||||||
|
@"location_id";
|
||||||
|
|
||||||
|
/// The chosen method of payment (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterPaymentType : @"Visa",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) =
|
||||||
|
@"payment_type";
|
||||||
|
|
||||||
|
/// The ID of a product promotion (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterPromotionID : @"ABC123",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) =
|
||||||
|
@"promotion_id";
|
||||||
|
|
||||||
|
/// The name of a product promotion (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterPromotionName : @"Summer Sale",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) =
|
||||||
|
@"promotion_name";
|
||||||
|
|
||||||
|
/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item
|
||||||
|
/// (NSString).
|
||||||
|
/// <pre>
|
||||||
|
/// NSDictionary *params = @{
|
||||||
|
/// kFIRParameterShippingTier : @"Ground",
|
||||||
|
/// // ...
|
||||||
|
/// };
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) =
|
||||||
|
@"shipping_tier";
|
|
@ -0,0 +1,29 @@
|
||||||
|
/// @file FIRUserPropertyNames.h
|
||||||
|
///
|
||||||
|
/// Predefined user property names.
|
||||||
|
///
|
||||||
|
/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can
|
||||||
|
/// later analyze different behaviors of various segments of your userbase. You may supply up to 25
|
||||||
|
/// unique UserProperties per app, and you can use the name and value of your choosing for each one.
|
||||||
|
/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and
|
||||||
|
/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to
|
||||||
|
/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not
|
||||||
|
/// be used.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/// The method used to sign in. For example, "google", "facebook" or "twitter".
|
||||||
|
static NSString *const kFIRUserPropertySignUpMethod
|
||||||
|
NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method";
|
||||||
|
|
||||||
|
/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user.
|
||||||
|
/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the
|
||||||
|
/// <a href="https://firebase.google.com/support/guides/disable-analytics">documentation</a> for
|
||||||
|
/// more details and information about related settings.
|
||||||
|
///
|
||||||
|
/// <pre>
|
||||||
|
/// [FIRAnalytics setUserPropertyString:@"NO"
|
||||||
|
/// forName:kFIRUserPropertyAllowAdPersonalizationSignals];
|
||||||
|
/// </pre>
|
||||||
|
static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals
|
||||||
|
NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads";
|
|
@ -0,0 +1,6 @@
|
||||||
|
#import "FIRAnalytics+AppDelegate.h"
|
||||||
|
#import "FIRAnalytics+Consent.h"
|
||||||
|
#import "FIRAnalytics.h"
|
||||||
|
#import "FIREventNames.h"
|
||||||
|
#import "FIRParameterNames.h"
|
||||||
|
#import "FIRUserPropertyNames.h"
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>FirebaseAnalytics</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.firebase.Firebase-FirebaseAnalytics</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>FirebaseAnalytics</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>8.0.0</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>iphonesimulator11.2</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,13 @@
|
||||||
|
framework module FirebaseAnalytics {
|
||||||
|
umbrella header "FirebaseAnalytics.h"
|
||||||
|
export *
|
||||||
|
module * { export * }
|
||||||
|
link framework "CoreTelephony"
|
||||||
|
link framework "Foundation"
|
||||||
|
link framework "Security"
|
||||||
|
link framework "SystemConfiguration"
|
||||||
|
link framework "UIKit"
|
||||||
|
link "c++"
|
||||||
|
link "sqlite3"
|
||||||
|
link "z"
|
||||||
|
}
|
|
@ -22,18 +22,20 @@
|
||||||
#import <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Public/FIRApp.h"
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h"
|
#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h"
|
||||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||||
#import "FirebaseCore/Sources/FIRComponentContainerInternal.h"
|
#import "FirebaseCore/Sources/FIRComponentContainerInternal.h"
|
||||||
#import "FirebaseCore/Sources/FIRConfigurationInternal.h"
|
#import "FirebaseCore/Sources/FIRConfigurationInternal.h"
|
||||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h"
|
#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||||
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||||
|
|
||||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
|
|
||||||
|
@ -71,8 +73,6 @@ NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat =
|
||||||
NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey =
|
NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey =
|
||||||
@"FirebaseDataCollectionDefaultEnabled";
|
@"FirebaseDataCollectionDefaultEnabled";
|
||||||
|
|
||||||
NSString *const kFIRAppDiagnosticsNotification = @"FIRAppDiagnosticsNotification";
|
|
||||||
|
|
||||||
NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType";
|
NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType";
|
||||||
NSString *const kFIRAppDiagnosticsErrorKey = @"Error";
|
NSString *const kFIRAppDiagnosticsErrorKey = @"Error";
|
||||||
NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp";
|
NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp";
|
||||||
|
@ -90,6 +90,14 @@ NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey =
|
||||||
NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey =
|
NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey =
|
||||||
@"FIRAuthStateDidChangeInternalNotificationUIDKey";
|
@"FIRAuthStateDidChangeInternalNotificationUIDKey";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error domain for exceptions and NSError construction.
|
||||||
|
*/
|
||||||
|
NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core";
|
||||||
|
|
||||||
|
/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */
|
||||||
|
NSString *const kFirebaseCoreDefaultsSuiteName = @"com.firebase.core";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL to download plist files.
|
* The URL to download plist files.
|
||||||
*/
|
*/
|
||||||
|
@ -116,8 +124,6 @@ static NSMutableArray<Class<FIRLibrary>> *sRegisteredAsConfigurable;
|
||||||
|
|
||||||
static NSMutableDictionary *sAllApps;
|
static NSMutableDictionary *sAllApps;
|
||||||
static FIRApp *sDefaultApp;
|
static FIRApp *sDefaultApp;
|
||||||
static NSMutableDictionary *sLibraryVersions;
|
|
||||||
static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|
||||||
|
|
||||||
+ (void)configure {
|
+ (void)configure {
|
||||||
FIROptions *options = [FIROptions defaultOptions];
|
FIROptions *options = [FIROptions defaultOptions];
|
||||||
|
@ -277,9 +283,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
sDefaultApp = nil;
|
sDefaultApp = nil;
|
||||||
[sAllApps removeAllObjects];
|
[sAllApps removeAllObjects];
|
||||||
sAllApps = nil;
|
sAllApps = nil;
|
||||||
[sLibraryVersions removeAllObjects];
|
[[self userAgent] reset];
|
||||||
sLibraryVersions = nil;
|
|
||||||
sFirebaseUserAgentOnceToken = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,9 +349,6 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self logCoreTelemetryIfEnabled];
|
|
||||||
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
// Initialize the Analytics once there is a valid options under default app. Analytics should
|
// Initialize the Analytics once there is a valid options under default app. Analytics should
|
||||||
// always initialize first by itself before the other SDKs.
|
// always initialize first by itself before the other SDKs.
|
||||||
if ([self.name isEqualToString:kFIRDefaultAppName]) {
|
if ([self.name isEqualToString:kFIRDefaultAppName]) {
|
||||||
|
@ -368,7 +369,6 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
[self subscribeForAppDidBecomeActiveNotifications];
|
[self subscribeForAppDidBecomeActiveNotifications];
|
||||||
|
|
||||||
|
@ -479,20 +479,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
NSLocalizedRecoverySuggestionErrorKey :
|
NSLocalizedRecoverySuggestionErrorKey :
|
||||||
@"Check formatting and location of GoogleService-Info.plist."
|
@"Check formatting and location of GoogleService-Info.plist."
|
||||||
};
|
};
|
||||||
return [NSError errorWithDomain:kFirebaseCoreErrorDomain
|
return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-100 userInfo:errorDict];
|
||||||
code:FIRErrorCodeInvalidPlistFile
|
|
||||||
userInfo:errorDict];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSError *)errorForSubspecConfigurationFailureWithDomain:(NSString *)domain
|
|
||||||
errorCode:(FIRErrorCode)code
|
|
||||||
service:(NSString *)service
|
|
||||||
reason:(NSString *)reason {
|
|
||||||
NSString *description =
|
|
||||||
[NSString stringWithFormat:@"Configuration failed for service %@.", service];
|
|
||||||
NSDictionary *errorDict =
|
|
||||||
@{NSLocalizedDescriptionKey : description, NSLocalizedFailureReasonErrorKey : reason};
|
|
||||||
return [NSError errorWithDomain:domain code:code userInfo:errorDict];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSError *)errorForInvalidAppID {
|
+ (NSError *)errorForInvalidAppID {
|
||||||
|
@ -502,9 +489,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
@"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the "
|
@"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the "
|
||||||
@"customized options."
|
@"customized options."
|
||||||
};
|
};
|
||||||
return [NSError errorWithDomain:kFirebaseCoreErrorDomain
|
return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-101 userInfo:errorDict];
|
||||||
code:FIRErrorCodeInvalidAppID
|
|
||||||
userInfo:errorDict];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL)isDefaultAppConfigured {
|
+ (BOOL)isDefaultAppConfigured {
|
||||||
|
@ -520,12 +505,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
// add the name/version pair to the dictionary.
|
// add the name/version pair to the dictionary.
|
||||||
if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound &&
|
if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound &&
|
||||||
[version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) {
|
[version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) {
|
||||||
@synchronized(self) {
|
[[self userAgent] setValue:version forComponent:name];
|
||||||
if (!sLibraryVersions) {
|
|
||||||
sLibraryVersions = [[NSMutableDictionary alloc] init];
|
|
||||||
}
|
|
||||||
sLibraryVersions[name] = version;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
FIRLogError(kFIRLoggerCore, @"I-COR000027",
|
FIRLogError(kFIRLoggerCore, @"I-COR000027",
|
||||||
@"The library name (%@) or version number (%@) contain invalid characters. "
|
@"The library name (%@) or version number (%@) contain invalid characters. "
|
||||||
|
@ -534,6 +514,11 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
|
||||||
|
withName:(nonnull NSString *)name {
|
||||||
|
[self registerInternalLibrary:library withName:name withVersion:FIRFirebaseVersion()];
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
|
+ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
|
||||||
withName:(nonnull NSString *)name
|
withName:(nonnull NSString *)name
|
||||||
withVersion:(nonnull NSString *)version {
|
withVersion:(nonnull NSString *)version {
|
||||||
|
@ -561,73 +546,18 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
[self registerLibrary:name withVersion:version];
|
[self registerLibrary:name withVersion:version];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (FIRFirebaseUserAgent *)userAgent {
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
static FIRFirebaseUserAgent *_userAgent;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
_userAgent = [[FIRFirebaseUserAgent alloc] init];
|
||||||
|
[_userAgent setValue:FIRFirebaseVersion() forComponent:@"fire-ios"];
|
||||||
|
});
|
||||||
|
return _userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
+ (NSString *)firebaseUserAgent {
|
+ (NSString *)firebaseUserAgent {
|
||||||
@synchronized(self) {
|
return [[self userAgent] firebaseUserAgent];
|
||||||
dispatch_once(&sFirebaseUserAgentOnceToken, ^{
|
|
||||||
// Report FirebaseCore version for useragent string
|
|
||||||
[FIRApp registerLibrary:@"fire-ios"
|
|
||||||
withVersion:[NSString stringWithUTF8String:FIRCoreVersionString]];
|
|
||||||
|
|
||||||
NSDictionary<NSString *, id> *info = [[NSBundle mainBundle] infoDictionary];
|
|
||||||
NSString *xcodeVersion = info[@"DTXcodeBuild"];
|
|
||||||
NSString *sdkVersion = info[@"DTSDKBuild"];
|
|
||||||
if (xcodeVersion) {
|
|
||||||
[FIRApp registerLibrary:@"xcode" withVersion:xcodeVersion];
|
|
||||||
}
|
|
||||||
if (sdkVersion) {
|
|
||||||
[FIRApp registerLibrary:@"apple-sdk" withVersion:sdkVersion];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *swiftFlagValue = [self hasSwiftRuntime] ? @"true" : @"false";
|
|
||||||
[FIRApp registerLibrary:@"swift" withVersion:swiftFlagValue];
|
|
||||||
|
|
||||||
[FIRApp registerLibrary:kFIRAppDiagnosticsApplePlatformPrefix
|
|
||||||
withVersion:[self applePlatform]];
|
|
||||||
});
|
|
||||||
|
|
||||||
NSMutableArray<NSString *> *libraries =
|
|
||||||
[[NSMutableArray<NSString *> alloc] initWithCapacity:sLibraryVersions.count];
|
|
||||||
for (NSString *libraryName in sLibraryVersions) {
|
|
||||||
[libraries addObject:[NSString stringWithFormat:@"%@/%@", libraryName,
|
|
||||||
sLibraryVersions[libraryName]]];
|
|
||||||
}
|
|
||||||
[libraries sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
|
|
||||||
return [libraries componentsJoinedByString:@" "];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL)hasSwiftRuntime {
|
|
||||||
// The class
|
|
||||||
// [Swift._SwiftObject](https://github.com/apple/swift/blob/5eac3e2818eb340b11232aff83edfbd1c307fa03/stdlib/public/runtime/SwiftObject.h#L35)
|
|
||||||
// is a part of Swift runtime, so it should be present if Swift runtime is available.
|
|
||||||
|
|
||||||
BOOL hasSwiftRuntime =
|
|
||||||
objc_lookUpClass("Swift._SwiftObject") != nil ||
|
|
||||||
// Swift object class name before
|
|
||||||
// https://github.com/apple/swift/commit/9637b4a6e11ddca72f5f6dbe528efc7c92f14d01
|
|
||||||
objc_getClass("_TtCs12_SwiftObject") != nil;
|
|
||||||
|
|
||||||
return hasSwiftRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)applePlatform {
|
|
||||||
NSString *applePlatform = @"unknown";
|
|
||||||
|
|
||||||
// When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are
|
|
||||||
// `true`, which means the condition list is order-sensitive.
|
|
||||||
#if TARGET_OS_MACCATALYST
|
|
||||||
applePlatform = @"maccatalyst";
|
|
||||||
#elif TARGET_OS_IOS
|
|
||||||
applePlatform = @"ios";
|
|
||||||
#elif TARGET_OS_TV
|
|
||||||
applePlatform = @"tvos";
|
|
||||||
#elif TARGET_OS_OSX
|
|
||||||
applePlatform = @"macos";
|
|
||||||
#elif TARGET_OS_WATCH
|
|
||||||
applePlatform = @"watchos";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return applePlatform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)checkExpectedBundleID {
|
- (void)checkExpectedBundleID {
|
||||||
|
@ -897,17 +827,6 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
return collectionEnabledPlistObject;
|
return collectionEnabledPlistObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Sending Logs
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
|
||||||
- (void)sendLogsWithServiceName:(NSString *)serviceName
|
|
||||||
version:(NSString *)version
|
|
||||||
error:(NSError *)error {
|
|
||||||
// Do nothing. Please remove calls to this method.
|
|
||||||
}
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
#pragma mark - App Life Cycle
|
#pragma mark - App Life Cycle
|
||||||
|
|
||||||
- (void)subscribeForAppDidBecomeActiveNotifications {
|
- (void)subscribeForAppDidBecomeActiveNotifications {
|
||||||
|
@ -931,7 +850,9 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||||
|
|
||||||
- (void)logCoreTelemetryIfEnabled {
|
- (void)logCoreTelemetryIfEnabled {
|
||||||
if ([self isDataCollectionDefaultEnabled]) {
|
if ([self isDataCollectionDefaultEnabled]) {
|
||||||
[FIRCoreDiagnosticsConnector logCoreTelemetryWithOptions:_options];
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
|
||||||
|
[FIRCoreDiagnosticsConnector logCoreTelemetryWithOptions:[self options]];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||||
|
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||||
|
|
||||||
@class FIRApp;
|
@class FIRApp;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "FIRConfiguration.h"
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h"
|
||||||
|
|
||||||
@class FIRAnalyticsConfiguration;
|
@class FIRAnalyticsConfiguration;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h"
|
#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Public/FIROptions.h"
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/FIRDiagnosticsData.h"
|
#import "FirebaseCore/Sources/FIRDiagnosticsData.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/FIRDiagnosticsData.h"
|
#import "FirebaseCore/Sources/FIRDiagnosticsData.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Public/FIRApp.h"
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright 2017 Google
|
|
||||||
//
|
|
||||||
// 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 "FirebaseCore/Sources/Private/FIRErrors.h"
|
|
||||||
|
|
||||||
NSString *const kFirebaseErrorDomain = @"com.firebase";
|
|
||||||
NSString *const kFirebaseConfigErrorDomain = @"com.firebase.config";
|
|
||||||
NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core";
|
|
||||||
NSString *const kFirebasePerfErrorDomain = @"com.firebase.perf";
|
|
||||||
NSString *const kFirebaseStorageErrorDomain = @"com.firebase.storage";
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019 Google
|
* Copyright 2020 Google LLC
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,18 +18,18 @@
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/** This class represents a future data object, determined at instantiation time. */
|
@interface FIRFirebaseUserAgent : NSObject
|
||||||
@interface GDTCORDataFuture : NSObject <NSSecureCoding>
|
|
||||||
|
|
||||||
/** If not nil, this data future was instantiated with this file URL. */
|
/** Returns the firebase user agent which consists of environment part and the components added via
|
||||||
@property(nullable, readonly, nonatomic) NSURL *fileURL;
|
* `setValue:forComponent` method. */
|
||||||
|
- (NSString *)firebaseUserAgent;
|
||||||
|
|
||||||
/** Initializes an instance with the given the fileURL.
|
/** Sets value associated with the specified component. If value is `nil` then the component is
|
||||||
*
|
* removed. */
|
||||||
* @param fileURL The fileURL containing the data to return in -data.
|
- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName;
|
||||||
* @return An instance of this class.
|
|
||||||
*/
|
/** Resets manually added components. */
|
||||||
- (instancetype)initWithFileURL:(NSURL *)fileURL;
|
- (void)reset;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Google LLC
|
||||||
|
*
|
||||||
|
* 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 "FirebaseCore/Sources/FIRFirebaseUserAgent.h"
|
||||||
|
|
||||||
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
|
|
||||||
|
@interface FIRFirebaseUserAgent ()
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) NSMutableDictionary<NSString *, NSString *> *valuesByComponent;
|
||||||
|
@property(nonatomic, readonly) NSDictionary<NSString *, NSString *> *environmentComponents;
|
||||||
|
@property(nonatomic, readonly) NSString *firebaseUserAgent;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FIRFirebaseUserAgent
|
||||||
|
|
||||||
|
@synthesize firebaseUserAgent = _firebaseUserAgent;
|
||||||
|
@synthesize environmentComponents = _environmentComponents;
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_valuesByComponent = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)firebaseUserAgent {
|
||||||
|
@synchronized(self) {
|
||||||
|
if (_firebaseUserAgent == nil) {
|
||||||
|
NSMutableDictionary<NSString *, NSString *> *allComponents =
|
||||||
|
[self.valuesByComponent mutableCopy];
|
||||||
|
[allComponents setValuesForKeysWithDictionary:self.environmentComponents];
|
||||||
|
|
||||||
|
__block NSMutableArray<NSString *> *components =
|
||||||
|
[[NSMutableArray<NSString *> alloc] initWithCapacity:self.valuesByComponent.count];
|
||||||
|
[allComponents enumerateKeysAndObjectsUsingBlock:^(
|
||||||
|
NSString *_Nonnull name, NSString *_Nonnull value, BOOL *_Nonnull stop) {
|
||||||
|
[components addObject:[NSString stringWithFormat:@"%@/%@", name, value]];
|
||||||
|
}];
|
||||||
|
[components sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
|
||||||
|
_firebaseUserAgent = [components componentsJoinedByString:@" "];
|
||||||
|
}
|
||||||
|
return _firebaseUserAgent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName {
|
||||||
|
@synchronized(self) {
|
||||||
|
self.valuesByComponent[componentName] = value;
|
||||||
|
// Reset cached user agent string.
|
||||||
|
_firebaseUserAgent = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reset {
|
||||||
|
@synchronized(self) {
|
||||||
|
// Reset components.
|
||||||
|
_valuesByComponent = [[[self class] environmentComponents] mutableCopy];
|
||||||
|
// Reset cached user agent string.
|
||||||
|
_firebaseUserAgent = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Environment components
|
||||||
|
|
||||||
|
- (NSDictionary<NSString *, NSString *> *)environmentComponents {
|
||||||
|
if (_environmentComponents == nil) {
|
||||||
|
_environmentComponents = [[self class] environmentComponents];
|
||||||
|
}
|
||||||
|
return _environmentComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary<NSString *, NSString *> *)environmentComponents {
|
||||||
|
NSMutableDictionary<NSString *, NSString *> *components = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
NSDictionary<NSString *, id> *info = [[NSBundle mainBundle] infoDictionary];
|
||||||
|
NSString *xcodeVersion = info[@"DTXcodeBuild"];
|
||||||
|
NSString *appleSdkVersion = info[@"DTSDKBuild"];
|
||||||
|
|
||||||
|
NSString *swiftFlagValue = [GULAppEnvironmentUtil hasSwiftRuntime] ? @"true" : @"false";
|
||||||
|
NSString *isFromAppstoreFlagValue = [GULAppEnvironmentUtil isFromAppStore] ? @"true" : @"false";
|
||||||
|
|
||||||
|
components[@"apple-platform"] = [GULAppEnvironmentUtil applePlatform];
|
||||||
|
components[@"apple-sdk"] = appleSdkVersion;
|
||||||
|
components[@"appstore"] = isFromAppstoreFlagValue;
|
||||||
|
components[@"deploy"] = [GULAppEnvironmentUtil deploymentType];
|
||||||
|
components[@"device"] = [GULAppEnvironmentUtil deviceModel];
|
||||||
|
components[@"os-version"] = [GULAppEnvironmentUtil systemVersion];
|
||||||
|
components[@"swift"] = swiftFlagValue;
|
||||||
|
components[@"xcode"] = xcodeVersion;
|
||||||
|
|
||||||
|
return [components copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -13,8 +13,11 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
||||||
|
#import <GoogleUtilities/GULHeartbeatDateStorable.h>
|
||||||
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||||
|
#import <GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h>
|
||||||
#import <GoogleUtilities/GULLogger.h>
|
#import <GoogleUtilities/GULLogger.h>
|
||||||
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
|
|
||||||
const static long secondsInDay = 86400;
|
const static long secondsInDay = 86400;
|
||||||
@implementation FIRHeartbeatInfo : NSObject
|
@implementation FIRHeartbeatInfo : NSObject
|
||||||
|
@ -25,9 +28,17 @@ const static long secondsInDay = 86400;
|
||||||
*/
|
*/
|
||||||
+ (BOOL)updateIfNeededHeartbeatDateForTag:(NSString *)heartbeatTag {
|
+ (BOOL)updateIfNeededHeartbeatDateForTag:(NSString *)heartbeatTag {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
NSString *const kHeartbeatStorageFile = @"HEARTBEAT_INFO_STORAGE";
|
NSString *const kHeartbeatStorageName = @"HEARTBEAT_INFO_STORAGE";
|
||||||
GULHeartbeatDateStorage *dataStorage =
|
id<GULHeartbeatDateStorable> dataStorage;
|
||||||
[[GULHeartbeatDateStorage alloc] initWithFileName:kHeartbeatStorageFile];
|
#if TARGET_OS_TV
|
||||||
|
NSUserDefaults *defaults =
|
||||||
|
[[NSUserDefaults alloc] initWithSuiteName:kFirebaseCoreDefaultsSuiteName];
|
||||||
|
dataStorage =
|
||||||
|
[[GULHeartbeatDateStorageUserDefaults alloc] initWithDefaults:defaults
|
||||||
|
key:kHeartbeatStorageName];
|
||||||
|
#else
|
||||||
|
dataStorage = [[GULHeartbeatDateStorage alloc] initWithFileName:kHeartbeatStorageName];
|
||||||
|
#endif
|
||||||
NSDate *heartbeatTime = [dataStorage heartbeatDateForTag:heartbeatTag];
|
NSDate *heartbeatTime = [dataStorage heartbeatDateForTag:heartbeatTag];
|
||||||
NSDate *currentDate = [NSDate date];
|
NSDate *currentDate = [NSDate date];
|
||||||
if (heartbeatTime != nil) {
|
if (heartbeatTime != nil) {
|
||||||
|
|
|
@ -16,20 +16,15 @@
|
||||||
|
|
||||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
#import <GoogleUtilities/GULLogger.h>
|
#import <GoogleUtilities/GULLogger.h>
|
||||||
#import "FirebaseCore/Sources/Public/FIRLoggerLevel.h"
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h"
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||||
|
|
||||||
FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]";
|
FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]";
|
||||||
|
|
||||||
// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones!
|
// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones!
|
||||||
FIRLoggerService kFIRLoggerABTesting = @"[Firebase/ABTesting]";
|
|
||||||
FIRLoggerService kFIRLoggerAdMob = @"[Firebase/AdMob]";
|
|
||||||
FIRLoggerService kFIRLoggerAnalytics = @"[Firebase/Analytics]";
|
FIRLoggerService kFIRLoggerAnalytics = @"[Firebase/Analytics]";
|
||||||
FIRLoggerService kFIRLoggerAuth = @"[Firebase/Auth]";
|
|
||||||
FIRLoggerService kFIRLoggerCrash = @"[Firebase/Crash]";
|
FIRLoggerService kFIRLoggerCrash = @"[Firebase/Crash]";
|
||||||
FIRLoggerService kFIRLoggerMLKit = @"[Firebase/MLKit]";
|
|
||||||
FIRLoggerService kFIRLoggerPerf = @"[Firebase/Performance]";
|
|
||||||
FIRLoggerService kFIRLoggerRemoteConfig = @"[Firebase/RemoteConfig]";
|
FIRLoggerService kFIRLoggerRemoteConfig = @"[Firebase/RemoteConfig]";
|
||||||
|
|
||||||
/// Arguments passed on launch.
|
/// Arguments passed on launch.
|
||||||
|
@ -58,10 +53,10 @@ static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$";
|
||||||
static NSRegularExpression *sMessageCodeRegex;
|
static NSRegularExpression *sMessageCodeRegex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void FIRLoggerInitializeASL() {
|
void FIRLoggerInitializeASL(void) {
|
||||||
dispatch_once(&sFIRLoggerOnceToken, ^{
|
dispatch_once(&sFIRLoggerOnceToken, ^{
|
||||||
// Register Firebase Version with GULLogger.
|
// Register Firebase Version with GULLogger.
|
||||||
GULLoggerRegisterVersion(FIRVersionString);
|
GULLoggerRegisterVersion(FIRFirebaseVersion());
|
||||||
|
|
||||||
// Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in.
|
// Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in.
|
||||||
NSArray *arguments = [NSProcessInfo processInfo].arguments;
|
NSArray *arguments = [NSProcessInfo processInfo].arguments;
|
||||||
|
@ -101,7 +96,7 @@ void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void FIRResetLogger() {
|
void FIRResetLogger(void) {
|
||||||
extern void GULResetLogger(void);
|
extern void GULResetLogger(void);
|
||||||
sFIRLoggerOnceToken = 0;
|
sFIRLoggerOnceToken = 0;
|
||||||
[sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey];
|
[sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey];
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||||
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||||
|
|
||||||
// Keys for the strings in the plist file.
|
// Keys for the strings in the plist file.
|
||||||
NSString *const kFIRAPIKey = @"API_KEY";
|
NSString *const kFIRAPIKey = @"API_KEY";
|
||||||
|
@ -90,40 +90,40 @@ NSString *const kFIRExceptionBadModification =
|
||||||
|
|
||||||
static FIROptions *sDefaultOptions = nil;
|
static FIROptions *sDefaultOptions = nil;
|
||||||
static NSDictionary *sDefaultOptionsDictionary = nil;
|
static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
|
static dispatch_once_t sDefaultOptionsOnceToken;
|
||||||
|
static dispatch_once_t sDefaultOptionsDictionaryOnceToken;
|
||||||
|
|
||||||
#pragma mark - Public only for internal class methods
|
#pragma mark - Public only for internal class methods
|
||||||
|
|
||||||
+ (FIROptions *)defaultOptions {
|
+ (FIROptions *)defaultOptions {
|
||||||
if (sDefaultOptions != nil) {
|
dispatch_once(&sDefaultOptionsOnceToken, ^{
|
||||||
return sDefaultOptions;
|
NSDictionary *defaultOptionsDictionary = [self defaultOptionsDictionary];
|
||||||
}
|
if (defaultOptionsDictionary != nil) {
|
||||||
|
sDefaultOptions =
|
||||||
|
[[FIROptions alloc] initInternalWithOptionsDictionary:defaultOptionsDictionary];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
NSDictionary *defaultOptionsDictionary = [self defaultOptionsDictionary];
|
|
||||||
if (defaultOptionsDictionary == nil) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
sDefaultOptions = [[FIROptions alloc] initInternalWithOptionsDictionary:defaultOptionsDictionary];
|
|
||||||
return sDefaultOptions;
|
return sDefaultOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Private class methods
|
#pragma mark - Private class methods
|
||||||
|
|
||||||
+ (NSDictionary *)defaultOptionsDictionary {
|
+ (NSDictionary *)defaultOptionsDictionary {
|
||||||
if (sDefaultOptionsDictionary != nil) {
|
dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{
|
||||||
return sDefaultOptionsDictionary;
|
NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName];
|
||||||
}
|
if (plistFilePath == nil) {
|
||||||
NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName];
|
return;
|
||||||
if (plistFilePath == nil) {
|
}
|
||||||
return nil;
|
sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
||||||
}
|
if (sDefaultOptionsDictionary == nil) {
|
||||||
sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
FIRLogError(kFIRLoggerCore, @"I-COR000011",
|
||||||
if (sDefaultOptionsDictionary == nil) {
|
@"The configuration file is not a dictionary: "
|
||||||
FIRLogError(kFIRLoggerCore, @"I-COR000011",
|
@"'%@.%@'.",
|
||||||
@"The configuration file is not a dictionary: "
|
kServiceInfoFileName, kServiceInfoFileType);
|
||||||
@"'%@.%@'.",
|
}
|
||||||
kServiceInfoFileName, kServiceInfoFileType);
|
});
|
||||||
}
|
|
||||||
return sDefaultOptionsDictionary;
|
return sDefaultOptionsDictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +144,8 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
+ (void)resetDefaultOptions {
|
+ (void)resetDefaultOptions {
|
||||||
sDefaultOptions = nil;
|
sDefaultOptions = nil;
|
||||||
sDefaultOptionsDictionary = nil;
|
sDefaultOptionsDictionary = nil;
|
||||||
|
sDefaultOptionsOnceToken = 0;
|
||||||
|
sDefaultOptionsDictionaryOnceToken = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Private instance methods
|
#pragma mark - Private instance methods
|
||||||
|
@ -158,9 +160,9 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)copyWithZone:(NSZone *)zone {
|
- (id)copyWithZone:(NSZone *)zone {
|
||||||
FIROptions *newOptions = [[[self class] allocWithZone:zone] init];
|
FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone]
|
||||||
|
initInternalWithOptionsDictionary:self.optionsDictionary];
|
||||||
if (newOptions) {
|
if (newOptions) {
|
||||||
newOptions.optionsDictionary = self.optionsDictionary;
|
|
||||||
newOptions.deepLinkURLScheme = self.deepLinkURLScheme;
|
newOptions.deepLinkURLScheme = self.deepLinkURLScheme;
|
||||||
newOptions.appGroupID = self.appGroupID;
|
newOptions.appGroupID = self.appGroupID;
|
||||||
newOptions.editingLocked = self.isEditingLocked;
|
newOptions.editingLocked = self.isEditingLocked;
|
||||||
|
@ -171,6 +173,12 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
|
|
||||||
#pragma mark - Public instance methods
|
#pragma mark - Public instance methods
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
// Unavailable.
|
||||||
|
[self doesNotRecognizeSelector:_cmd];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (instancetype)initWithContentsOfFile:(NSString *)plistPath {
|
- (instancetype)initWithContentsOfFile:(NSString *)plistPath {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
|
@ -277,7 +285,7 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
// The unit tests are set up to catch anything that does not properly convert.
|
// The unit tests are set up to catch anything that does not properly convert.
|
||||||
NSString *version = [NSString stringWithUTF8String:FIRCoreVersionString];
|
NSString *version = FIRFirebaseVersion();
|
||||||
NSArray *components = [version componentsSeparatedByString:@"."];
|
NSArray *components = [version componentsSeparatedByString:@"."];
|
||||||
NSString *major = [components objectAtIndex:0];
|
NSString *major = [components objectAtIndex:0];
|
||||||
NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]];
|
NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]];
|
||||||
|
|
|
@ -14,14 +14,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||||
|
|
||||||
#ifndef Firebase_VERSION
|
#ifndef Firebase_VERSION
|
||||||
#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation"
|
#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FIRCore_VERSION
|
|
||||||
#error "FIRCore_VERSION is not defined: add -DFIRCore_VERSION=... to the build invocation"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The following two macros supply the incantation so that the C
|
// The following two macros supply the incantation so that the C
|
||||||
// preprocessor does not try to parse the version as a floating
|
// preprocessor does not try to parse the version as a floating
|
||||||
// point number. See
|
// point number. See
|
||||||
|
@ -29,5 +27,6 @@
|
||||||
#define STR(x) STR_EXPAND(x)
|
#define STR(x) STR_EXPAND(x)
|
||||||
#define STR_EXPAND(x) #x
|
#define STR_EXPAND(x) #x
|
||||||
|
|
||||||
const char *const FIRVersionString = (const char *const)STR(Firebase_VERSION);
|
NSString* FIRFirebaseVersion(void) {
|
||||||
const char *const FIRCoreVersionString = (const char *const)STR(FIRCore_VERSION);
|
return @STR(Firebase_VERSION);
|
||||||
|
}
|
||||||
|
|
|
@ -14,19 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if SWIFT_PACKAGE
|
|
||||||
// TODO(paulb777): Investigate if there's a common strategy for both Cocoapods and Swift PM.
|
|
||||||
#import "FIRApp.h"
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FIRApp.h>
|
#import <FirebaseCore/FIRApp.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
// The has_include is a workaround so the old IID needed for the FIS tests can find FIRErrors.h
|
|
||||||
#if __has_include("FirebaseCore/Sources/Private/FIRErrors.h")
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRErrors.h"
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FIRErrors.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@class FIRComponentContainer;
|
@class FIRComponentContainer;
|
||||||
@protocol FIRLibrary;
|
@protocol FIRLibrary;
|
||||||
|
@ -51,6 +39,10 @@ extern NSString *const kFIRAppDeleteNotification;
|
||||||
extern NSString *const kFIRAppIsDefaultAppKey;
|
extern NSString *const kFIRAppIsDefaultAppKey;
|
||||||
extern NSString *const kFIRAppNameKey;
|
extern NSString *const kFIRAppNameKey;
|
||||||
extern NSString *const kFIRGoogleAppIDKey;
|
extern NSString *const kFIRGoogleAppIDKey;
|
||||||
|
extern NSString *const kFirebaseCoreErrorDomain;
|
||||||
|
|
||||||
|
/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */
|
||||||
|
extern NSString *const kFirebaseCoreDefaultsSuiteName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The format string for the User Defaults key used for storing the data collection enabled flag.
|
* The format string for the User Defaults key used for storing the data collection enabled flag.
|
||||||
|
@ -63,11 +55,6 @@ extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat;
|
||||||
*/
|
*/
|
||||||
extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey;
|
extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey;
|
||||||
|
|
||||||
/**
|
|
||||||
* A notification fired containing diagnostic information when SDK errors occur.
|
|
||||||
*/
|
|
||||||
extern NSString *const kFIRAppDiagnosticsNotification;
|
|
||||||
|
|
||||||
/** @var FIRAuthStateDidChangeInternalNotification
|
/** @var FIRAuthStateDidChangeInternalNotification
|
||||||
@brief The name of the @c NSNotificationCenter notification which is posted when the auth state
|
@brief The name of the @c NSNotificationCenter notification which is posted when the auth state
|
||||||
changes (e.g. a new token has been produced, a user logs in or out). The object parameter of
|
changes (e.g. a new token has been produced, a user logs in or out). The object parameter of
|
||||||
|
@ -110,14 +97,6 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
||||||
*/
|
*/
|
||||||
@property(nonatomic) FIRComponentContainer *container;
|
@property(nonatomic) FIRComponentContainer *container;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an error for failing to configure a subspec service. This method is called by each
|
|
||||||
* FIRApp notification listener.
|
|
||||||
*/
|
|
||||||
+ (NSError *)errorForSubspecConfigurationFailureWithDomain:(NSString *)domain
|
|
||||||
errorCode:(FIRErrorCode)code
|
|
||||||
service:(NSString *)service
|
|
||||||
reason:(NSString *)reason;
|
|
||||||
/**
|
/**
|
||||||
* Checks if the default app is configured without trying to configure it.
|
* Checks if the default app is configured without trying to configure it.
|
||||||
*/
|
*/
|
||||||
|
@ -132,9 +111,19 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
||||||
*/
|
*/
|
||||||
+ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version;
|
+ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a given internal library to be reported for analytics.
|
||||||
|
*
|
||||||
|
* @param library Optional parameter for component registration.
|
||||||
|
* @param name Name of the library.
|
||||||
|
*/
|
||||||
|
+ (void)registerInternalLibrary:(nonnull Class<FIRLibrary>)library
|
||||||
|
withName:(nonnull NSString *)name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a given internal library with the given version number to be reported for
|
* Registers a given internal library with the given version number to be reported for
|
||||||
* analytics.
|
* analytics. This should only be used for non-Firebase libraries that have their own versioning
|
||||||
|
* scheme.
|
||||||
*
|
*
|
||||||
* @param library Optional parameter for component registration.
|
* @param library Optional parameter for component registration.
|
||||||
* @param name Name of the library.
|
* @param name Name of the library.
|
||||||
|
@ -149,15 +138,6 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
||||||
*/
|
*/
|
||||||
+ (NSString *)firebaseUserAgent;
|
+ (NSString *)firebaseUserAgent;
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by each SDK to send logs about SDK configuration status to Clearcut.
|
|
||||||
*
|
|
||||||
* @note This API is a no-op, please remove calls to it.
|
|
||||||
*/
|
|
||||||
- (void)sendLogsWithServiceName:(NSString *)serviceName
|
|
||||||
version:(NSString *)version
|
|
||||||
error:(NSError *)error;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be used by the unit tests in eack SDK to reset FIRApp. This method is thread unsafe.
|
* Can be used by the unit tests in eack SDK to reset FIRApp. This method is thread unsafe.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,15 +15,6 @@
|
||||||
*/
|
*/
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
// The has_include is a workaround so the old IID needed for the FIS tests can find the headers.
|
|
||||||
#if __has_include("FirebaseCore/Sources/Private/FIRComponentType.h")
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRComponentType.h"
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FIRComponentType.h>
|
|
||||||
#import <FirebaseCore/FIRLibrary.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/// A type-safe macro to retrieve a component from a container. This should be used to retrieve
|
/// A type-safe macro to retrieve a component from a container. This should be used to retrieve
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 Google
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Error codes in Firebase error domain. */
|
|
||||||
typedef NS_ENUM(NSInteger, FIRErrorCode) {
|
|
||||||
/**
|
|
||||||
* Unknown error.
|
|
||||||
*/
|
|
||||||
FIRErrorCodeUnknown = 0,
|
|
||||||
/**
|
|
||||||
* Loading data from the GoogleService-Info.plist file failed. This is a fatal error and should
|
|
||||||
* not be ignored. Further calls to the API will fail and/or possibly cause crashes.
|
|
||||||
*/
|
|
||||||
FIRErrorCodeInvalidPlistFile = -100,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validating the Google App ID format failed.
|
|
||||||
*/
|
|
||||||
FIRErrorCodeInvalidAppID = -101,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error code for failing to configure a specific service. It's deprecated, but
|
|
||||||
* still used after copybara.
|
|
||||||
*/
|
|
||||||
FIRErrorCodeConfigFailed = -114,
|
|
||||||
};
|
|
|
@ -27,7 +27,7 @@ typedef NS_ENUM(NSInteger, FIRHeartbeatInfoCode) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get heartbeat code requred for the sdk.
|
* Get heartbeat code required for the sdk.
|
||||||
* @param heartbeatTag String representing the sdk heartbeat tag.
|
* @param heartbeatTag String representing the sdk heartbeat tag.
|
||||||
* @return Heartbeat code indicating whether or not an sdk/global heartbeat
|
* @return Heartbeat code indicating whether or not an sdk/global heartbeat
|
||||||
* needs to be sent
|
* needs to be sent
|
||||||
|
|
|
@ -19,14 +19,8 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
// The has_include is a workaround so the old IID needed for the FIS tests can find the headers.
|
|
||||||
#if __has_include("FirebaseCore/Sources/Private/FIRComponent.h")
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FIRComponent.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@class FIRApp;
|
@class FIRApp;
|
||||||
|
@class FIRComponent;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,7 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#if SWIFT_PACKAGE
|
|
||||||
// TODO(paulb777): Investigate if there's a common strategy for both Cocoapods and Swift PM.
|
|
||||||
#import "FIRLoggerLevel.h"
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FIRLoggerLevel.h>
|
#import <FirebaseCore/FIRLoggerLevel.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@ -30,14 +25,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
*/
|
*/
|
||||||
typedef NSString *const FIRLoggerService;
|
typedef NSString *const FIRLoggerService;
|
||||||
|
|
||||||
extern FIRLoggerService kFIRLoggerABTesting;
|
|
||||||
extern FIRLoggerService kFIRLoggerAdMob;
|
|
||||||
extern FIRLoggerService kFIRLoggerAnalytics;
|
extern FIRLoggerService kFIRLoggerAnalytics;
|
||||||
extern FIRLoggerService kFIRLoggerAuth;
|
|
||||||
extern FIRLoggerService kFIRLoggerCrash;
|
extern FIRLoggerService kFIRLoggerCrash;
|
||||||
extern FIRLoggerService kFIRLoggerCore;
|
extern FIRLoggerService kFIRLoggerCore;
|
||||||
extern FIRLoggerService kFIRLoggerMLKit;
|
|
||||||
extern FIRLoggerService kFIRLoggerPerf;
|
|
||||||
extern FIRLoggerService kFIRLoggerRemoteConfig;
|
extern FIRLoggerService kFIRLoggerRemoteConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,12 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if SWIFT_PACKAGE
|
|
||||||
// TODO(paulb777): Investigate if there's a common strategy for both Cocoapods and Swift PM.
|
|
||||||
#import "FIROptions.h"
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FIROptions.h>
|
#import <FirebaseCore/FIROptions.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keys for the strings in the plist file.
|
* Keys for the strings in the plist file.
|
||||||
|
@ -56,7 +51,8 @@ extern NSString *const kServiceInfoFileType;
|
||||||
* Initializes the options with dictionary. The above strings are the keys of the dictionary.
|
* Initializes the options with dictionary. The above strings are the keys of the dictionary.
|
||||||
* This is the designated initializer.
|
* This is the designated initializer.
|
||||||
*/
|
*/
|
||||||
- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary;
|
- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary
|
||||||
|
NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* defaultOptions and defaultOptionsDictionary are exposed in order to be used in FIRApp and
|
* defaultOptions and defaultOptionsDictionary are exposed in order to be used in FIRApp and
|
||||||
|
|
|
@ -15,15 +15,12 @@
|
||||||
// An umbrella header, for any other libraries in this repo to access Firebase Public and Private
|
// An umbrella header, for any other libraries in this repo to access Firebase Public and Private
|
||||||
// headers. Any package manager complexity should be handled here.
|
// headers. Any package manager complexity should be handled here.
|
||||||
|
|
||||||
#if SWIFT_PACKAGE
|
|
||||||
@import FirebaseCore;
|
|
||||||
#else
|
|
||||||
#import <FirebaseCore/FirebaseCore.h>
|
#import <FirebaseCore/FirebaseCore.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||||
|
#import "FirebaseCore/Sources/Private/FIRComponentType.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
||||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||||
|
|
|
@ -106,7 +106,7 @@ NS_SWIFT_NAME(FirebaseOptions)
|
||||||
* FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
|
* FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
|
||||||
* Returns nil if the plist file does not exist or is invalid.
|
* Returns nil if the plist file does not exist or is invalid.
|
||||||
*/
|
*/
|
||||||
- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath;
|
- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a customized instance of FIROptions with required fields. Use the mutable properties
|
* Initializes a customized instance of FIROptions with required fields. Use the mutable properties
|
||||||
|
@ -115,9 +115,12 @@ NS_SWIFT_NAME(FirebaseOptions)
|
||||||
// clang-format off
|
// clang-format off
|
||||||
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
|
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
|
||||||
GCMSenderID:(NSString *)GCMSenderID
|
GCMSenderID:(NSString *)GCMSenderID
|
||||||
NS_SWIFT_NAME(init(googleAppID:gcmSenderID:));
|
NS_SWIFT_NAME(init(googleAppID:gcmSenderID:)) NS_DESIGNATED_INITIALIZER;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
/** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Google
|
* Copyright 2020 Google LLC
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#include "FIRErrorCode.h"
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
extern NSString *const kFirebaseErrorDomain;
|
/** Returns the current version of Firebase. */
|
||||||
extern NSString *const kFirebaseConfigErrorDomain;
|
NS_SWIFT_NAME(FirebaseVersion())
|
||||||
extern NSString *const kFirebaseCoreErrorDomain;
|
NSString* FIRFirebaseVersion(void);
|
||||||
extern NSString *const kFirebasePerfErrorDomain;
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -18,3 +18,4 @@
|
||||||
#import "FIRConfiguration.h"
|
#import "FIRConfiguration.h"
|
||||||
#import "FIRLoggerLevel.h"
|
#import "FIRLoggerLevel.h"
|
||||||
#import "FIROptions.h"
|
#import "FIROptions.h"
|
||||||
|
#import "FIRVersion.h"
|
|
@ -3,8 +3,12 @@
|
||||||
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
|
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
|
||||||
|
|
||||||
[![Actions Status][gh-abtesting-badge]][gh-actions]
|
[![Actions Status][gh-abtesting-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-appcheck-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-appdistribution-badge]][gh-actions]
|
||||||
[![Actions Status][gh-auth-badge]][gh-actions]
|
[![Actions Status][gh-auth-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-cocoapods-integration-badge]][gh-actions]
|
||||||
[![Actions Status][gh-core-badge]][gh-actions]
|
[![Actions Status][gh-core-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-core-diagnostics-badge]][gh-actions]
|
||||||
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
||||||
[![Actions Status][gh-database-badge]][gh-actions]
|
[![Actions Status][gh-database-badge]][gh-actions]
|
||||||
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
||||||
|
@ -12,9 +16,13 @@
|
||||||
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
||||||
[![Actions Status][gh-firestore-badge]][gh-actions]
|
[![Actions Status][gh-firestore-badge]][gh-actions]
|
||||||
[![Actions Status][gh-functions-badge]][gh-actions]
|
[![Actions Status][gh-functions-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-google-utilities-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-google-utilities-components-badge]][gh-actions]
|
||||||
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
|
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
|
||||||
[![Actions Status][gh-interop-badge]][gh-actions]
|
[![Actions Status][gh-interop-badge]][gh-actions]
|
||||||
[![Actions Status][gh-messaging-badge]][gh-actions]
|
[![Actions Status][gh-messaging-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-mlmodeldownloader-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-performance-badge]][gh-actions]
|
||||||
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
|
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
|
||||||
[![Actions Status][gh-storage-badge]][gh-actions]
|
[![Actions Status][gh-storage-badge]][gh-actions]
|
||||||
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
||||||
|
@ -23,21 +31,23 @@
|
||||||
|
|
||||||
# Firebase Apple Open Source Development
|
# Firebase Apple Open Source Development
|
||||||
|
|
||||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
|
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
|
||||||
FirebasePerformance, and FirebaseML.
|
and FirebaseML.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
|
||||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
|
||||||
a set of utilities used by Firebase and other Google products.
|
|
||||||
|
|
||||||
Firebase is an app development platform with tools to help you build, grow and
|
Firebase is an app development platform with tools to help you build, grow and
|
||||||
monetize your app. More information about Firebase can be found at
|
monetize your app. More information about Firebase can be found at
|
||||||
[https://firebase.google.com](https://firebase.google.com).
|
[https://firebase.google.com](https://firebase.google.com).
|
||||||
|
|
||||||
|
The repository also includes GoogleUtilities and GoogleDataTransport source
|
||||||
|
which are utilities used by Firebase and other Google products.
|
||||||
|
|
||||||
|
**Note** _FirebaseCombineSwift_ contains support for Apple's Combine framework. This module is currently under development, and not yet supported for use in production environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
See the three subsections for details about three different installation methods.
|
See the subsections below for details about the different installation methods.
|
||||||
1. [Standard pod install](README.md#standard-pod-install)
|
1. [Standard pod install](README.md#standard-pod-install)
|
||||||
|
1. [Swift Package Manager](SwiftPackageManager.md)
|
||||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||||
1. [Experimental Carthage](README.md#carthage-ios-only)
|
1. [Experimental Carthage](README.md#carthage-ios-only)
|
||||||
|
|
||||||
|
@ -46,11 +56,12 @@ See the three subsections for details about three different installation methods
|
||||||
Go to
|
Go to
|
||||||
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
||||||
|
|
||||||
### Installing from GitHub
|
### Swift Package Manager
|
||||||
|
|
||||||
For releases starting with 5.0.0, the source for each release is also deployed
|
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
|
||||||
to CocoaPods master and available via standard
|
found at [SwiftPackageManager.md](SwiftPackageManager.md).
|
||||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
|
||||||
|
### Installing from GitHub
|
||||||
|
|
||||||
These instructions can be used to access the Firebase repo at other branches,
|
These instructions can be used to access the Firebase repo at other branches,
|
||||||
tags, or commits.
|
tags, or commits.
|
||||||
|
@ -67,14 +78,14 @@ All of the official releases are tagged in this repo and available via CocoaPods
|
||||||
source snapshot or unreleased branch, use Podfile directives like the following:
|
source snapshot or unreleased branch, use Podfile directives like the following:
|
||||||
|
|
||||||
To access FirebaseFirestore via a branch:
|
To access FirebaseFirestore via a branch:
|
||||||
```
|
```ruby
|
||||||
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
```
|
```
|
||||||
|
|
||||||
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
||||||
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
```
|
```
|
||||||
|
@ -82,12 +93,8 @@ pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
### Carthage (iOS only)
|
### Carthage (iOS only)
|
||||||
|
|
||||||
Instructions for the experimental Carthage distribution are at
|
Instructions for the experimental Carthage distribution are at
|
||||||
[Carthage](Carthage.md).
|
[Carthage](Carthage.md). If you have a new Mac with an Apple silicon chip, please see
|
||||||
|
[these instructions](AppleSilicon.md).
|
||||||
### Rome
|
|
||||||
|
|
||||||
Instructions for installing binary frameworks via
|
|
||||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
|
||||||
|
|
||||||
### Using Firebase from a Framework or a library
|
### Using Firebase from a Framework or a library
|
||||||
|
|
||||||
|
@ -98,13 +105,22 @@ Instructions for installing binary frameworks via
|
||||||
To develop Firebase software in this repository, ensure that you have at least
|
To develop Firebase software in this repository, ensure that you have at least
|
||||||
the following software:
|
the following software:
|
||||||
|
|
||||||
* Xcode 10.3 (or later)
|
* Xcode 12.2 (or later)
|
||||||
* CocoaPods 1.7.2 (or later)
|
|
||||||
|
CocoaPods is still the canonical way to develop, but much of the repo now supports
|
||||||
|
development with Swift Package Manager.
|
||||||
|
|
||||||
|
### CocoaPods
|
||||||
|
|
||||||
|
Install
|
||||||
|
* CocoaPods 1.10.0 (or later)
|
||||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||||
|
|
||||||
For the pod that you want to develop:
|
For the pod that you want to develop:
|
||||||
|
|
||||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
```ruby
|
||||||
|
pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios
|
||||||
|
```
|
||||||
|
|
||||||
Note: If the CocoaPods cache is out of date, you may need to run
|
Note: If the CocoaPods cache is out of date, you may need to run
|
||||||
`pod repo update` before the `pod gen` command.
|
`pod repo update` before the `pod gen` command.
|
||||||
|
@ -116,7 +132,7 @@ CocoaPods workspaces.
|
||||||
Firestore has a self contained Xcode project. See
|
Firestore has a self contained Xcode project. See
|
||||||
[Firestore/README.md](Firestore/README.md).
|
[Firestore/README.md](Firestore/README.md).
|
||||||
|
|
||||||
### Development for Catalyst
|
#### Development for Catalyst
|
||||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||||
* Check the Mac box in the App-iOS Build Settings
|
* Check the Mac box in the App-iOS Build Settings
|
||||||
* Sign the App in the Settings Signing & Capabilities tab
|
* Sign the App in the Settings Signing & Capabilities tab
|
||||||
|
@ -125,6 +141,18 @@ Firestore has a self contained Xcode project. See
|
||||||
* Select the Unit-unit scheme
|
* Select the Unit-unit scheme
|
||||||
* Run it to build and test
|
* Run it to build and test
|
||||||
|
|
||||||
|
Alternatively disable signing in each target:
|
||||||
|
* Go to Build Settings tab
|
||||||
|
* Click `+`
|
||||||
|
* Select `Add User-Defined Setting`
|
||||||
|
* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO`
|
||||||
|
|
||||||
|
### Swift Package Manager
|
||||||
|
* `open Package.swift` or double click `Package.swift` in Finder.
|
||||||
|
* Xcode will open the project
|
||||||
|
* Choose a scheme for a library to build or test suite to run
|
||||||
|
* Choose a target platform by selecting the run destination along with the scheme
|
||||||
|
|
||||||
### Adding a New Firebase Pod
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
See [AddNewPod.md](AddNewPod.md).
|
See [AddNewPod.md](AddNewPod.md).
|
||||||
|
@ -136,40 +164,24 @@ See [HeadersImports.md](HeadersImports.md).
|
||||||
### Code Formatting
|
### Code Formatting
|
||||||
|
|
||||||
To ensure that the code is formatted consistently, run the script
|
To ensure that the code is formatted consistently, run the script
|
||||||
[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
|
[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh)
|
||||||
before creating a PR.
|
before creating a PR.
|
||||||
|
|
||||||
Travis will verify that any code changes are done in a style compliant way. Install
|
GitHub Actions will verify that any code changes are done in a style compliant
|
||||||
`clang-format` and `swiftformat`.
|
way. Install `clang-format` and `mint`:
|
||||||
These commands will get the right versions:
|
|
||||||
|
|
||||||
|
```console
|
||||||
|
brew install clang-format@12
|
||||||
|
brew install mint
|
||||||
```
|
```
|
||||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/c6f1cbd/Formula/clang-format.rb
|
|
||||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/c13eda8/Formula/swiftformat.rb
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: if you already have a newer version of these installed you may need to
|
|
||||||
`brew switch` to this version.
|
|
||||||
|
|
||||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
|
||||||
match the versions in the CI failure logs
|
|
||||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
|
||||||
|
|
||||||
### Running Unit Tests
|
### Running Unit Tests
|
||||||
|
|
||||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||||
|
|
||||||
#### Viewing Code Coverage (Deprecated)
|
|
||||||
|
|
||||||
First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
|
|
||||||
|
|
||||||
After running the `AllUnitTests_iOS` scheme in Xcode, execute
|
|
||||||
`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
|
|
||||||
at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
|
|
||||||
|
|
||||||
### Running Sample Apps
|
### Running Sample Apps
|
||||||
In order to run the sample apps and integration tests, you'll need valid
|
In order to run the sample apps and integration tests, you'll need a valid
|
||||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist
|
||||||
files without real values, but can be replaced with real plist files. To get your own
|
files without real values, but can be replaced with real plist files. To get your own
|
||||||
`GoogleService-Info.plist` files:
|
`GoogleService-Info.plist` files:
|
||||||
|
|
||||||
|
@ -177,12 +189,11 @@ files without real values, but can be replaced with real plist files. To get you
|
||||||
2. Create a new Firebase project, if you don't already have one
|
2. Create a new Firebase project, if you don't already have one
|
||||||
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
||||||
identifier (e.g. `com.google.Database-Example`)
|
identifier (e.g. `com.google.Database-Example`)
|
||||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
|
||||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
|
||||||
|
|
||||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
### Coverage Report Generation
|
||||||
special Apple capabilities, and you will have to change the sample app to use a unique bundle
|
|
||||||
identifier that you can control in your own Apple Developer account.
|
See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md).
|
||||||
|
|
||||||
## Specific Component Instructions
|
## Specific Component Instructions
|
||||||
See the sections below for any special instructions for those components.
|
See the sections below for any special instructions for those components.
|
||||||
|
@ -202,10 +213,16 @@ To run against a local emulator instance, invoke `./scripts/run_database_emulato
|
||||||
running the integration test.
|
running the integration test.
|
||||||
|
|
||||||
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
|
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
|
||||||
`Example/Database/App/GoogleService-Info.plist`. Your Security Rule must be set to
|
`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to
|
||||||
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
|
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
|
||||||
running.
|
running.
|
||||||
|
|
||||||
|
### Firebase Performance Monitoring
|
||||||
|
If you're doing specific Firebase Performance Monitoring development, see
|
||||||
|
[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK
|
||||||
|
and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about
|
||||||
|
integrating Performance with the dev test App.
|
||||||
|
|
||||||
### Firebase Storage
|
### Firebase Storage
|
||||||
|
|
||||||
To run the Storage Integration tests, follow the instructions in
|
To run the Storage Integration tests, follow the instructions in
|
||||||
|
@ -219,7 +236,8 @@ In order to actually test receiving push notifications, you will need to:
|
||||||
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
||||||
account, and enable that App ID for push notifications.
|
account, and enable that App ID for push notifications.
|
||||||
2. You'll also need to
|
2. You'll also need to
|
||||||
[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
[upload your APNs Provider Authentication Key or certificate to the
|
||||||
|
Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
||||||
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
||||||
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
||||||
|
|
||||||
|
@ -229,43 +247,39 @@ The iOS Simulator cannot register for remote notifications, and will not receive
|
||||||
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
||||||
physical device.
|
physical device.
|
||||||
|
|
||||||
## Community Supported Efforts
|
## Building with Firebase on Apple platforms
|
||||||
|
|
||||||
|
At this time, not all of Firebase's products are available across all Apple platforms. However,
|
||||||
|
Firebase is constantly evolving and community supported efforts have helped expand Firebase's support.
|
||||||
|
To keep up with the latest info regarding Firebase's support across Apple platforms, refer to
|
||||||
|
[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform)
|
||||||
|
in Firebase's documentation.
|
||||||
|
|
||||||
|
### Community Supported Efforts
|
||||||
|
|
||||||
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
||||||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||||
participate in the Firebase community.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### tvOS, macOS, watchOS and Catalyst
|
#### tvOS, macOS, watchOS and Catalyst
|
||||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and
|
||||||
tvOS, macOS, watchOS and Catalyst.
|
work on tvOS, macOS, watchOS and Catalyst.
|
||||||
|
|
||||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
For tvOS, see the [Sample](Example/tvOSSample).
|
||||||
For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
|
For watchOS, currently only Messaging, Storage and Crashlytics (and their dependencies) have limited
|
||||||
[Independent Watch App Sample](Example/watchOSSample).
|
support. See the [Independent Watch App Sample](Example/watchOSSample).
|
||||||
|
|
||||||
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and this
|
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and
|
||||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
this repository is actively developed primarily for iOS. While we can catch basic unit test issues
|
||||||
Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
|
with GitHub Actions, there may be some changes where the SDK no longer works as expected on macOS,
|
||||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
tvOS or watchOS. If you encounter this, please
|
||||||
|
[file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||||
|
|
||||||
During app setup in the console, you may get to a step that mentions something like "Checking if the app
|
During app setup in the console, you may get to a step that mentions something like "Checking if the
|
||||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
|
app has communicated with our servers". This relies on Analytics and will not work on
|
||||||
|
macOS/tvOS/watchOS/Catalyst.
|
||||||
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
||||||
|
|
||||||
To install, add a subset of the following to the Podfile:
|
|
||||||
|
|
||||||
```
|
|
||||||
pod 'Firebase/ABTesting' # No watchOS support yet
|
|
||||||
pod 'Firebase/Auth' # No watchOS support yet
|
|
||||||
pod 'Firebase/Crashlytics' # No watchOS support yet
|
|
||||||
pod 'Firebase/Database' # No watchOS support yet
|
|
||||||
pod 'Firebase/Firestore' # No watchOS support yet
|
|
||||||
pod 'Firebase/Functions' # No watchOS support yet
|
|
||||||
pod 'Firebase/Messaging'
|
|
||||||
pod 'Firebase/RemoteConfig' # No watchOS support yet
|
|
||||||
pod 'Firebase/Storage'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Additional Catalyst Notes
|
#### Additional Catalyst Notes
|
||||||
|
|
||||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||||
|
@ -273,6 +287,10 @@ to Build Settings.
|
||||||
* FirebaseFirestore requires signing the
|
* FirebaseFirestore requires signing the
|
||||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||||
|
|
||||||
|
#### Additional Crashlytics Notes
|
||||||
|
* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are
|
||||||
|
not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded)
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
@ -293,8 +311,12 @@ Your use of Firebase is governed by the
|
||||||
|
|
||||||
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
|
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
|
||||||
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
|
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
|
||||||
|
[gh-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg
|
||||||
|
[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg
|
||||||
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
|
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
|
||||||
|
[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg
|
||||||
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
|
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
|
||||||
|
[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/badge.svg
|
||||||
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
|
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
|
||||||
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
|
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
|
||||||
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
|
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
|
||||||
|
@ -302,9 +324,13 @@ Your use of Firebase is governed by the
|
||||||
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
|
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
|
||||||
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
|
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
|
||||||
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
|
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
|
||||||
|
[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg
|
||||||
|
[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/badge.svg
|
||||||
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
|
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
|
||||||
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
|
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
|
||||||
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
|
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
|
||||||
|
[gh-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg
|
||||||
|
[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/badge.svg
|
||||||
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
|
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
|
||||||
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
|
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
|
||||||
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
|
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
|
||||||
|
|
|
@ -17,10 +17,7 @@
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
|
#import <GoogleDataTransport/GoogleDataTransport.h>
|
||||||
#import <GoogleDataTransport/GDTCOREvent.h>
|
|
||||||
#import <GoogleDataTransport/GDTCORTargets.h>
|
|
||||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
|
||||||
|
|
||||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||||
|
@ -33,7 +30,7 @@
|
||||||
#import <nanopb/pb_decode.h>
|
#import <nanopb/pb_decode.h>
|
||||||
#import <nanopb/pb_encode.h>
|
#import <nanopb/pb_encode.h>
|
||||||
|
|
||||||
#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
|
#import "Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
|
||||||
|
|
||||||
/** The logger service string to use when printing to the console. */
|
/** The logger service string to use when printing to the console. */
|
||||||
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
||||||
|
@ -44,7 +41,9 @@ static BOOL kUsingZipFile = YES;
|
||||||
static BOOL kUsingZipFile = NO;
|
static BOOL kUsingZipFile = NO;
|
||||||
#endif // FIREBASE_BUILD_ZIP_FILE
|
#endif // FIREBASE_BUILD_ZIP_FILE
|
||||||
|
|
||||||
#ifdef FIREBASE_BUILD_CARTHAGE
|
#if SWIFT_PACKAGE
|
||||||
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM
|
||||||
|
#elif FIREBASE_BUILD_CARTHAGE
|
||||||
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE
|
||||||
#elif FIREBASE_BUILD_ZIP_FILE
|
#elif FIREBASE_BUILD_ZIP_FILE
|
||||||
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE
|
||||||
|
@ -52,13 +51,6 @@ static BOOL kUsingZipFile = NO;
|
||||||
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS
|
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static NSString *const kFIRServiceMLVisionOnDeviceAutoML = @"MLVisionOnDeviceAutoML";
|
|
||||||
static NSString *const kFIRServiceMLVisionOnDeviceFace = @"MLVisionOnDeviceFace";
|
|
||||||
static NSString *const kFIRServiceMLVisionOnDeviceBarcode = @"MLVisionOnDeviceBarcode";
|
|
||||||
static NSString *const kFIRServiceMLVisionOnDeviceText = @"MLVisionOnDeviceText";
|
|
||||||
static NSString *const kFIRServiceMLVisionOnDeviceLabel = @"MLVisionOnDeviceLabel";
|
|
||||||
static NSString *const kFIRServiceMLVisionOnDeviceObjectDetection =
|
|
||||||
@"MLVisionOnDeviceObjectDetection";
|
|
||||||
static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter";
|
static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter";
|
||||||
|
|
||||||
static NSString *const kFIRServiceAdMob = @"AdMob";
|
static NSString *const kFIRServiceAdMob = @"AdMob";
|
||||||
|
@ -200,24 +192,6 @@ NS_ASSUME_NONNULL_END
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Metadata helpers
|
|
||||||
|
|
||||||
/** Returns the model of iOS device. Sample platform strings are @"iPhone7,1" for iPhone 6 Plus,
|
|
||||||
* @"iPhone7,2" for iPhone 6, etc. Refer to the Hardware strings at
|
|
||||||
* https://en.wikipedia.org/wiki/List_of_iOS_devices
|
|
||||||
*
|
|
||||||
* @return The device model as an NSString.
|
|
||||||
*/
|
|
||||||
+ (NSString *)deviceModel {
|
|
||||||
static NSString *deviceModel = nil;
|
|
||||||
if (deviceModel == nil) {
|
|
||||||
struct utsname systemInfo;
|
|
||||||
uname(&systemInfo);
|
|
||||||
deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
|
|
||||||
}
|
|
||||||
return deviceModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - nanopb helper functions
|
#pragma mark - nanopb helper functions
|
||||||
|
|
||||||
/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array.
|
/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array.
|
||||||
|
@ -270,18 +244,6 @@ logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringT
|
||||||
kFIRServicePerformance :
|
kFIRServicePerformance :
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE),
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE),
|
||||||
kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE),
|
kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE),
|
||||||
kFIRServiceMLVisionOnDeviceAutoML :
|
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML),
|
|
||||||
kFIRServiceMLVisionOnDeviceFace :
|
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE),
|
|
||||||
kFIRServiceMLVisionOnDeviceBarcode :
|
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE),
|
|
||||||
kFIRServiceMLVisionOnDeviceText :
|
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT),
|
|
||||||
kFIRServiceMLVisionOnDeviceLabel :
|
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL),
|
|
||||||
kFIRServiceMLVisionOnDeviceObjectDetection : @(
|
|
||||||
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION),
|
|
||||||
kFIRServiceMLModelInterpreter :
|
kFIRServiceMLModelInterpreter :
|
||||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER),
|
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER),
|
||||||
kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS),
|
kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS),
|
||||||
|
@ -379,7 +341,7 @@ void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfigu
|
||||||
config->icore_version = FIREncodeString(libraryVersionID);
|
config->icore_version = FIREncodeString(libraryVersionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *deviceModel = [FIRCoreDiagnostics deviceModel];
|
NSString *deviceModel = [GULAppEnvironmentUtil deviceModel];
|
||||||
if (deviceModel.length) {
|
if (deviceModel.length) {
|
||||||
config->device_model = FIREncodeString(deviceModel);
|
config->device_model = FIREncodeString(deviceModel);
|
||||||
}
|
}
|
||||||
|
@ -422,40 +384,6 @@ void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfigu
|
||||||
[sdkServiceInstalledArray
|
[sdkServiceInstalledArray
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))];
|
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))];
|
||||||
}
|
}
|
||||||
// ML Vision On Device AutoML.
|
|
||||||
if (NSClassFromString(@"FIRVisionOnDeviceAutoMLImageLabelerOptions") != nil) {
|
|
||||||
[sdkServiceInstalledArray
|
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceAutoML))];
|
|
||||||
}
|
|
||||||
// ML Vision On Device Face.
|
|
||||||
if (NSClassFromString(@"FIRVisionFaceDetector") != nil &&
|
|
||||||
NSClassFromString(@"GMVFaceDetector") != nil) {
|
|
||||||
[sdkServiceInstalledArray
|
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceFace))];
|
|
||||||
}
|
|
||||||
// ML Vision On Device Barcode.
|
|
||||||
if (NSClassFromString(@"FIRVisionBarcodeDetector") != nil &&
|
|
||||||
NSClassFromString(@"GMVBarcodeDetector") != nil) {
|
|
||||||
[sdkServiceInstalledArray
|
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceBarcode))];
|
|
||||||
}
|
|
||||||
// ML Vision On Device Text.
|
|
||||||
if (NSClassFromString(@"FIRVisionTextDetector") != nil &&
|
|
||||||
NSClassFromString(@"GMVTextDetector") != nil) {
|
|
||||||
[sdkServiceInstalledArray
|
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceText))];
|
|
||||||
}
|
|
||||||
// ML Vision On Device Image Label.
|
|
||||||
if (NSClassFromString(@"FIRVisionLabelDetector") != nil &&
|
|
||||||
NSClassFromString(@"GMVLabelDetector") != nil) {
|
|
||||||
[sdkServiceInstalledArray
|
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceLabel))];
|
|
||||||
}
|
|
||||||
// ML Vision On Device Object.
|
|
||||||
if (NSClassFromString(@"FIRVisionObjectDetector") != nil) {
|
|
||||||
[sdkServiceInstalledArray
|
|
||||||
addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceObjectDetection))];
|
|
||||||
}
|
|
||||||
// ML Model Interpreter
|
// ML Model Interpreter
|
||||||
if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) {
|
if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) {
|
||||||
[sdkServiceInstalledArray
|
[sdkServiceInstalledArray
|
||||||
|
@ -526,29 +454,6 @@ void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfigu
|
||||||
config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count;
|
config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Populates the proto with the number of linked frameworks.
|
|
||||||
*
|
|
||||||
* @param config The proto to populate.
|
|
||||||
*/
|
|
||||||
void FIRPopulateProtoWithNumberOfLinkedFrameworks(
|
|
||||||
logs_proto_mobilesdk_ios_ICoreConfiguration *config) {
|
|
||||||
int numFrameworks = -1; // Subtract the app binary itself.
|
|
||||||
unsigned int numImages;
|
|
||||||
const char **imageNames = objc_copyImageNames(&numImages);
|
|
||||||
for (unsigned int i = 0; i < numImages; i++) {
|
|
||||||
NSString *imageName = [NSString stringWithUTF8String:imageNames[i]];
|
|
||||||
if ([imageName rangeOfString:@"System/Library"].length != 0 // Apple .frameworks
|
|
||||||
|| [imageName rangeOfString:@"Developer/Library"].length != 0 // Xcode debug .frameworks
|
|
||||||
|| [imageName rangeOfString:@"usr/lib"].length != 0) { // Public .dylibs
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
numFrameworks++;
|
|
||||||
}
|
|
||||||
free(imageNames);
|
|
||||||
config->dynamic_framework_count = numFrameworks;
|
|
||||||
config->has_dynamic_framework_count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Populates the proto with Info.plist values.
|
/** Populates the proto with Info.plist values.
|
||||||
*
|
*
|
||||||
* @param config The proto to populate.
|
* @param config The proto to populate.
|
||||||
|
@ -604,7 +509,6 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
||||||
FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects);
|
FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects);
|
||||||
FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects);
|
FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects);
|
||||||
FIRPopulateProtoWithInstalledServices(&icore_config);
|
FIRPopulateProtoWithInstalledServices(&icore_config);
|
||||||
FIRPopulateProtoWithNumberOfLinkedFrameworks(&icore_config);
|
|
||||||
FIRPopulateProtoWithInfoPlistValues(&icore_config);
|
FIRPopulateProtoWithInfoPlistValues(&icore_config);
|
||||||
[self setHeartbeatFlagIfNeededToConfig:&icore_config];
|
[self setHeartbeatFlagIfNeededToConfig:&icore_config];
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Automatically generated nanopb constant definitions */
|
/* Automatically generated nanopb constant definitions */
|
||||||
/* Generated by nanopb-0.3.9.5 */
|
/* Generated by nanopb-0.3.9.7 */
|
||||||
|
|
||||||
#include "firebasecore.nanopb.h"
|
#include "firebasecore.nanopb.h"
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Automatically generated nanopb header */
|
/* Automatically generated nanopb header */
|
||||||
/* Generated by nanopb-0.3.9.5 */
|
/* Generated by nanopb-0.3.9.7 */
|
||||||
|
|
||||||
#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||||
#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019 Google
|
* Copyright 2020 Google LLC
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -14,6 +14,5 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
// There are no actual public headers in the lib. This is a dummy public header to prevent Cocoapods
|
||||||
|
// from adding all internal headers as public.
|
||||||
FOUNDATION_EXPORT const char *const FIRInstallationsVersionStr;
|
|
|
@ -3,8 +3,12 @@
|
||||||
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
|
[![Platform](https://img.shields.io/cocoapods/p/Firebase.svg?style=flat)](https://cocoapods.org/pods/Firebase)
|
||||||
|
|
||||||
[![Actions Status][gh-abtesting-badge]][gh-actions]
|
[![Actions Status][gh-abtesting-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-appcheck-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-appdistribution-badge]][gh-actions]
|
||||||
[![Actions Status][gh-auth-badge]][gh-actions]
|
[![Actions Status][gh-auth-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-cocoapods-integration-badge]][gh-actions]
|
||||||
[![Actions Status][gh-core-badge]][gh-actions]
|
[![Actions Status][gh-core-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-core-diagnostics-badge]][gh-actions]
|
||||||
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
||||||
[![Actions Status][gh-database-badge]][gh-actions]
|
[![Actions Status][gh-database-badge]][gh-actions]
|
||||||
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
||||||
|
@ -12,9 +16,13 @@
|
||||||
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
||||||
[![Actions Status][gh-firestore-badge]][gh-actions]
|
[![Actions Status][gh-firestore-badge]][gh-actions]
|
||||||
[![Actions Status][gh-functions-badge]][gh-actions]
|
[![Actions Status][gh-functions-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-google-utilities-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-google-utilities-components-badge]][gh-actions]
|
||||||
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
|
[![Actions Status][gh-inappmessaging-badge]][gh-actions]
|
||||||
[![Actions Status][gh-interop-badge]][gh-actions]
|
[![Actions Status][gh-interop-badge]][gh-actions]
|
||||||
[![Actions Status][gh-messaging-badge]][gh-actions]
|
[![Actions Status][gh-messaging-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-mlmodeldownloader-badge]][gh-actions]
|
||||||
|
[![Actions Status][gh-performance-badge]][gh-actions]
|
||||||
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
|
[![Actions Status][gh-remoteconfig-badge]][gh-actions]
|
||||||
[![Actions Status][gh-storage-badge]][gh-actions]
|
[![Actions Status][gh-storage-badge]][gh-actions]
|
||||||
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
||||||
|
@ -23,21 +31,23 @@
|
||||||
|
|
||||||
# Firebase Apple Open Source Development
|
# Firebase Apple Open Source Development
|
||||||
|
|
||||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
|
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
|
||||||
FirebasePerformance, and FirebaseML.
|
and FirebaseML.
|
||||||
|
|
||||||
The repository also includes GoogleUtilities source. The
|
|
||||||
[GoogleUtilities](GoogleUtilities/README.md) pod is
|
|
||||||
a set of utilities used by Firebase and other Google products.
|
|
||||||
|
|
||||||
Firebase is an app development platform with tools to help you build, grow and
|
Firebase is an app development platform with tools to help you build, grow and
|
||||||
monetize your app. More information about Firebase can be found at
|
monetize your app. More information about Firebase can be found at
|
||||||
[https://firebase.google.com](https://firebase.google.com).
|
[https://firebase.google.com](https://firebase.google.com).
|
||||||
|
|
||||||
|
The repository also includes GoogleUtilities and GoogleDataTransport source
|
||||||
|
which are utilities used by Firebase and other Google products.
|
||||||
|
|
||||||
|
**Note** _FirebaseCombineSwift_ contains support for Apple's Combine framework. This module is currently under development, and not yet supported for use in production environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
See the three subsections for details about three different installation methods.
|
See the subsections below for details about the different installation methods.
|
||||||
1. [Standard pod install](README.md#standard-pod-install)
|
1. [Standard pod install](README.md#standard-pod-install)
|
||||||
|
1. [Swift Package Manager](SwiftPackageManager.md)
|
||||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||||
1. [Experimental Carthage](README.md#carthage-ios-only)
|
1. [Experimental Carthage](README.md#carthage-ios-only)
|
||||||
|
|
||||||
|
@ -46,11 +56,12 @@ See the three subsections for details about three different installation methods
|
||||||
Go to
|
Go to
|
||||||
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
|
||||||
|
|
||||||
### Installing from GitHub
|
### Swift Package Manager
|
||||||
|
|
||||||
For releases starting with 5.0.0, the source for each release is also deployed
|
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
|
||||||
to CocoaPods master and available via standard
|
found at [SwiftPackageManager.md](SwiftPackageManager.md).
|
||||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
|
||||||
|
### Installing from GitHub
|
||||||
|
|
||||||
These instructions can be used to access the Firebase repo at other branches,
|
These instructions can be used to access the Firebase repo at other branches,
|
||||||
tags, or commits.
|
tags, or commits.
|
||||||
|
@ -67,14 +78,14 @@ All of the official releases are tagged in this repo and available via CocoaPods
|
||||||
source snapshot or unreleased branch, use Podfile directives like the following:
|
source snapshot or unreleased branch, use Podfile directives like the following:
|
||||||
|
|
||||||
To access FirebaseFirestore via a branch:
|
To access FirebaseFirestore via a branch:
|
||||||
```
|
```ruby
|
||||||
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
|
||||||
```
|
```
|
||||||
|
|
||||||
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
|
||||||
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
```
|
```
|
||||||
|
@ -82,12 +93,8 @@ pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||||
### Carthage (iOS only)
|
### Carthage (iOS only)
|
||||||
|
|
||||||
Instructions for the experimental Carthage distribution are at
|
Instructions for the experimental Carthage distribution are at
|
||||||
[Carthage](Carthage.md).
|
[Carthage](Carthage.md). If you have a new Mac with an Apple silicon chip, please see
|
||||||
|
[these instructions](AppleSilicon.md).
|
||||||
### Rome
|
|
||||||
|
|
||||||
Instructions for installing binary frameworks via
|
|
||||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
|
||||||
|
|
||||||
### Using Firebase from a Framework or a library
|
### Using Firebase from a Framework or a library
|
||||||
|
|
||||||
|
@ -98,13 +105,22 @@ Instructions for installing binary frameworks via
|
||||||
To develop Firebase software in this repository, ensure that you have at least
|
To develop Firebase software in this repository, ensure that you have at least
|
||||||
the following software:
|
the following software:
|
||||||
|
|
||||||
* Xcode 10.3 (or later)
|
* Xcode 12.2 (or later)
|
||||||
* CocoaPods 1.7.2 (or later)
|
|
||||||
|
CocoaPods is still the canonical way to develop, but much of the repo now supports
|
||||||
|
development with Swift Package Manager.
|
||||||
|
|
||||||
|
### CocoaPods
|
||||||
|
|
||||||
|
Install
|
||||||
|
* CocoaPods 1.10.0 (or later)
|
||||||
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
|
||||||
|
|
||||||
For the pod that you want to develop:
|
For the pod that you want to develop:
|
||||||
|
|
||||||
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
```ruby
|
||||||
|
pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios
|
||||||
|
```
|
||||||
|
|
||||||
Note: If the CocoaPods cache is out of date, you may need to run
|
Note: If the CocoaPods cache is out of date, you may need to run
|
||||||
`pod repo update` before the `pod gen` command.
|
`pod repo update` before the `pod gen` command.
|
||||||
|
@ -116,7 +132,7 @@ CocoaPods workspaces.
|
||||||
Firestore has a self contained Xcode project. See
|
Firestore has a self contained Xcode project. See
|
||||||
[Firestore/README.md](Firestore/README.md).
|
[Firestore/README.md](Firestore/README.md).
|
||||||
|
|
||||||
### Development for Catalyst
|
#### Development for Catalyst
|
||||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||||
* Check the Mac box in the App-iOS Build Settings
|
* Check the Mac box in the App-iOS Build Settings
|
||||||
* Sign the App in the Settings Signing & Capabilities tab
|
* Sign the App in the Settings Signing & Capabilities tab
|
||||||
|
@ -125,6 +141,18 @@ Firestore has a self contained Xcode project. See
|
||||||
* Select the Unit-unit scheme
|
* Select the Unit-unit scheme
|
||||||
* Run it to build and test
|
* Run it to build and test
|
||||||
|
|
||||||
|
Alternatively disable signing in each target:
|
||||||
|
* Go to Build Settings tab
|
||||||
|
* Click `+`
|
||||||
|
* Select `Add User-Defined Setting`
|
||||||
|
* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO`
|
||||||
|
|
||||||
|
### Swift Package Manager
|
||||||
|
* `open Package.swift` or double click `Package.swift` in Finder.
|
||||||
|
* Xcode will open the project
|
||||||
|
* Choose a scheme for a library to build or test suite to run
|
||||||
|
* Choose a target platform by selecting the run destination along with the scheme
|
||||||
|
|
||||||
### Adding a New Firebase Pod
|
### Adding a New Firebase Pod
|
||||||
|
|
||||||
See [AddNewPod.md](AddNewPod.md).
|
See [AddNewPod.md](AddNewPod.md).
|
||||||
|
@ -136,40 +164,24 @@ See [HeadersImports.md](HeadersImports.md).
|
||||||
### Code Formatting
|
### Code Formatting
|
||||||
|
|
||||||
To ensure that the code is formatted consistently, run the script
|
To ensure that the code is formatted consistently, run the script
|
||||||
[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh)
|
[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh)
|
||||||
before creating a PR.
|
before creating a PR.
|
||||||
|
|
||||||
Travis will verify that any code changes are done in a style compliant way. Install
|
GitHub Actions will verify that any code changes are done in a style compliant
|
||||||
`clang-format` and `swiftformat`.
|
way. Install `clang-format` and `mint`:
|
||||||
These commands will get the right versions:
|
|
||||||
|
|
||||||
|
```console
|
||||||
|
brew install clang-format@12
|
||||||
|
brew install mint
|
||||||
```
|
```
|
||||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/c6f1cbd/Formula/clang-format.rb
|
|
||||||
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/c13eda8/Formula/swiftformat.rb
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: if you already have a newer version of these installed you may need to
|
|
||||||
`brew switch` to this version.
|
|
||||||
|
|
||||||
To update this section, find the versions of clang-format and swiftformat.rb to
|
|
||||||
match the versions in the CI failure logs
|
|
||||||
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
|
|
||||||
|
|
||||||
### Running Unit Tests
|
### Running Unit Tests
|
||||||
|
|
||||||
Select a scheme and press Command-u to build a component and run its unit tests.
|
Select a scheme and press Command-u to build a component and run its unit tests.
|
||||||
|
|
||||||
#### Viewing Code Coverage (Deprecated)
|
|
||||||
|
|
||||||
First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`.
|
|
||||||
|
|
||||||
After running the `AllUnitTests_iOS` scheme in Xcode, execute
|
|
||||||
`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output`
|
|
||||||
at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results.
|
|
||||||
|
|
||||||
### Running Sample Apps
|
### Running Sample Apps
|
||||||
In order to run the sample apps and integration tests, you'll need valid
|
In order to run the sample apps and integration tests, you'll need a valid
|
||||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist
|
||||||
files without real values, but can be replaced with real plist files. To get your own
|
files without real values, but can be replaced with real plist files. To get your own
|
||||||
`GoogleService-Info.plist` files:
|
`GoogleService-Info.plist` files:
|
||||||
|
|
||||||
|
@ -177,12 +189,11 @@ files without real values, but can be replaced with real plist files. To get you
|
||||||
2. Create a new Firebase project, if you don't already have one
|
2. Create a new Firebase project, if you don't already have one
|
||||||
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
|
||||||
identifier (e.g. `com.google.Database-Example`)
|
identifier (e.g. `com.google.Database-Example`)
|
||||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
|
||||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
|
||||||
|
|
||||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
### Coverage Report Generation
|
||||||
special Apple capabilities, and you will have to change the sample app to use a unique bundle
|
|
||||||
identifier that you can control in your own Apple Developer account.
|
See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md).
|
||||||
|
|
||||||
## Specific Component Instructions
|
## Specific Component Instructions
|
||||||
See the sections below for any special instructions for those components.
|
See the sections below for any special instructions for those components.
|
||||||
|
@ -202,10 +213,16 @@ To run against a local emulator instance, invoke `./scripts/run_database_emulato
|
||||||
running the integration test.
|
running the integration test.
|
||||||
|
|
||||||
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
|
To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to
|
||||||
`Example/Database/App/GoogleService-Info.plist`. Your Security Rule must be set to
|
`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to
|
||||||
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
|
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
|
||||||
running.
|
running.
|
||||||
|
|
||||||
|
### Firebase Performance Monitoring
|
||||||
|
If you're doing specific Firebase Performance Monitoring development, see
|
||||||
|
[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK
|
||||||
|
and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about
|
||||||
|
integrating Performance with the dev test App.
|
||||||
|
|
||||||
### Firebase Storage
|
### Firebase Storage
|
||||||
|
|
||||||
To run the Storage Integration tests, follow the instructions in
|
To run the Storage Integration tests, follow the instructions in
|
||||||
|
@ -219,7 +236,8 @@ In order to actually test receiving push notifications, you will need to:
|
||||||
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
|
||||||
account, and enable that App ID for push notifications.
|
account, and enable that App ID for push notifications.
|
||||||
2. You'll also need to
|
2. You'll also need to
|
||||||
[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
[upload your APNs Provider Authentication Key or certificate to the
|
||||||
|
Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
|
||||||
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
|
||||||
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
|
||||||
|
|
||||||
|
@ -229,43 +247,39 @@ The iOS Simulator cannot register for remote notifications, and will not receive
|
||||||
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
In order to receive push notifications, you'll have to follow the steps above and run the app on a
|
||||||
physical device.
|
physical device.
|
||||||
|
|
||||||
## Community Supported Efforts
|
## Building with Firebase on Apple platforms
|
||||||
|
|
||||||
|
At this time, not all of Firebase's products are available across all Apple platforms. However,
|
||||||
|
Firebase is constantly evolving and community supported efforts have helped expand Firebase's support.
|
||||||
|
To keep up with the latest info regarding Firebase's support across Apple platforms, refer to
|
||||||
|
[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform)
|
||||||
|
in Firebase's documentation.
|
||||||
|
|
||||||
|
### Community Supported Efforts
|
||||||
|
|
||||||
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are
|
||||||
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
|
||||||
participate in the Firebase community.
|
participate in the Firebase community.
|
||||||
|
|
||||||
### tvOS, macOS, watchOS and Catalyst
|
#### tvOS, macOS, watchOS and Catalyst
|
||||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and
|
||||||
tvOS, macOS, watchOS and Catalyst.
|
work on tvOS, macOS, watchOS and Catalyst.
|
||||||
|
|
||||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
For tvOS, see the [Sample](Example/tvOSSample).
|
||||||
For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
|
For watchOS, currently only Messaging, Storage and Crashlytics (and their dependencies) have limited
|
||||||
[Independent Watch App Sample](Example/watchOSSample).
|
support. See the [Independent Watch App Sample](Example/watchOSSample).
|
||||||
|
|
||||||
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and this
|
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and
|
||||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
this repository is actively developed primarily for iOS. While we can catch basic unit test issues
|
||||||
Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
|
with GitHub Actions, there may be some changes where the SDK no longer works as expected on macOS,
|
||||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
tvOS or watchOS. If you encounter this, please
|
||||||
|
[file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||||
|
|
||||||
During app setup in the console, you may get to a step that mentions something like "Checking if the app
|
During app setup in the console, you may get to a step that mentions something like "Checking if the
|
||||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
|
app has communicated with our servers". This relies on Analytics and will not work on
|
||||||
|
macOS/tvOS/watchOS/Catalyst.
|
||||||
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
|
||||||
|
|
||||||
To install, add a subset of the following to the Podfile:
|
|
||||||
|
|
||||||
```
|
|
||||||
pod 'Firebase/ABTesting' # No watchOS support yet
|
|
||||||
pod 'Firebase/Auth' # No watchOS support yet
|
|
||||||
pod 'Firebase/Crashlytics' # No watchOS support yet
|
|
||||||
pod 'Firebase/Database' # No watchOS support yet
|
|
||||||
pod 'Firebase/Firestore' # No watchOS support yet
|
|
||||||
pod 'Firebase/Functions' # No watchOS support yet
|
|
||||||
pod 'Firebase/Messaging'
|
|
||||||
pod 'Firebase/RemoteConfig' # No watchOS support yet
|
|
||||||
pod 'Firebase/Storage'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Additional Catalyst Notes
|
#### Additional Catalyst Notes
|
||||||
|
|
||||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||||
|
@ -273,6 +287,10 @@ to Build Settings.
|
||||||
* FirebaseFirestore requires signing the
|
* FirebaseFirestore requires signing the
|
||||||
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681).
|
||||||
|
|
||||||
|
#### Additional Crashlytics Notes
|
||||||
|
* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are
|
||||||
|
not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded)
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source
|
||||||
|
@ -293,8 +311,12 @@ Your use of Firebase is governed by the
|
||||||
|
|
||||||
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
|
[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions
|
||||||
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
|
[gh-abtesting-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/abtesting/badge.svg
|
||||||
|
[gh-appcheck-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/app_check/badge.svg
|
||||||
|
[gh-appdistribution-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/appdistribution/badge.svg
|
||||||
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
|
[gh-auth-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/auth/badge.svg
|
||||||
|
[gh-cocoapods-integration-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/cocoapods-integration/badge.svg
|
||||||
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
|
[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg
|
||||||
|
[gh-core-diagnostics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core-diagnostics/badge.svg
|
||||||
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
|
[gh-crashlytics-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/crashlytics/badge.svg
|
||||||
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
|
[gh-database-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/database/badge.svg
|
||||||
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
|
[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg
|
||||||
|
@ -302,9 +324,13 @@ Your use of Firebase is governed by the
|
||||||
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
|
[gh-firebasepod-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firebasepod/badge.svg
|
||||||
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
|
[gh-firestore-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/firestore/badge.svg
|
||||||
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
|
[gh-functions-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/functions/badge.svg
|
||||||
|
[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg
|
||||||
|
[gh-google-utilities-components-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities-components/badge.svg
|
||||||
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
|
[gh-inappmessaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/inappmessaging/badge.svg
|
||||||
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
|
[gh-interop-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/interop/badge.svg
|
||||||
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
|
[gh-messaging-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/messaging/badge.svg
|
||||||
|
[gh-mlmodeldownloader-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/mlmodeldownloader/badge.svg
|
||||||
|
[gh-performance-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/performance/badge.svg
|
||||||
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
|
[gh-remoteconfig-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/remoteconfig/badge.svg
|
||||||
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
|
[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg
|
||||||
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
|
[gh-symbolcollision-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/symbolcollision/badge.svg
|
||||||
|
|
|
@ -47,6 +47,11 @@ NSString* FIRCLSApplicationGetSDKBundleID(void);
|
||||||
*/
|
*/
|
||||||
NSString* FIRCLSApplicationGetPlatform(void);
|
NSString* FIRCLSApplicationGetPlatform(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Operating System for filtering. Should be kept consistent with Analytics.
|
||||||
|
*/
|
||||||
|
NSString* FIRCLSApplicationGetFirebasePlatform(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the user-facing app name
|
* Returns the user-facing app name
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FIRCLSApplication.h"
|
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
|
|
||||||
#import "FIRCLSHost.h"
|
#import "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||||
#import "FIRCLSUtility.h"
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||||
|
|
||||||
#if CLS_TARGET_OS_OSX
|
#if CLS_TARGET_OS_OSX
|
||||||
#import <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
|
@ -44,9 +46,29 @@ NSString* FIRCLSApplicationGetPlatform(void) {
|
||||||
return @"mac";
|
return @"mac";
|
||||||
#elif TARGET_OS_TV
|
#elif TARGET_OS_TV
|
||||||
return @"tvos";
|
return @"tvos";
|
||||||
|
#elif TARGET_OS_WATCH
|
||||||
|
return @"ios"; // TODO: temporarily use iOS until Firebase can add watchos to the backend
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSString* FIRCLSApplicationGetFirebasePlatform(void) {
|
||||||
|
NSString* firebasePlatform = [GULAppEnvironmentUtil applePlatform];
|
||||||
|
|
||||||
|
#if TARGET_OS_IOS
|
||||||
|
if ([firebasePlatform isEqualToString:@"ios"] &&
|
||||||
|
UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||||
|
return @"ipados";
|
||||||
|
}
|
||||||
|
// This check is necessary because iOS-only apps running on iPad
|
||||||
|
// will report UIUserInterfaceIdiomPhone via UI_USER_INTERFACE_IDIOM().
|
||||||
|
if ([[UIDevice currentDevice].model.lowercaseString containsString:@"ipad"]) {
|
||||||
|
return @"ipados";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return firebasePlatform;
|
||||||
|
}
|
||||||
|
|
||||||
// these defaults match the FIRCLSInfoPlist helper in FIRCLSIDEFoundation
|
// these defaults match the FIRCLSInfoPlist helper in FIRCLSIDEFoundation
|
||||||
NSString* FIRCLSApplicationGetBundleVersion(void) {
|
NSString* FIRCLSApplicationGetBundleVersion(void) {
|
||||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "FIRCLSFeatures.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
#include "FIRCLSMachO.h"
|
#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSBinaryImage.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h"
|
||||||
|
|
||||||
#include <libkern/OSAtomic.h>
|
#include <libkern/OSAtomic.h>
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
|
@ -21,13 +21,13 @@
|
||||||
|
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
|
||||||
#include "FIRCLSByteUtility.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
#include "FIRCLSFeatures.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||||
#include "FIRCLSGlobals.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
#include "FIRCLSHost.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
#include "FIRCLSMachO.h"
|
#include "Crashlytics/Shared/FIRCLSByteUtility.h"
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
|
||||||
|
|
||||||
#include <dispatch/dispatch.h>
|
#include <dispatch/dispatch.h>
|
||||||
|
|
||||||
|
@ -363,20 +363,17 @@ static void FIRCLSBinaryImageChanged(bool added,
|
||||||
const struct mach_header* mh,
|
const struct mach_header* mh,
|
||||||
intptr_t vmaddr_slide) {
|
intptr_t vmaddr_slide) {
|
||||||
// FIRCLSSDKLog("Binary image %s %p\n", added ? "loaded" : "unloaded", mh);
|
// FIRCLSSDKLog("Binary image %s %p\n", added ? "loaded" : "unloaded", mh);
|
||||||
|
|
||||||
FIRCLSBinaryImageDetails imageDetails;
|
FIRCLSBinaryImageDetails imageDetails;
|
||||||
|
|
||||||
memset(&imageDetails, 0, sizeof(FIRCLSBinaryImageDetails));
|
memset(&imageDetails, 0, sizeof(FIRCLSBinaryImageDetails));
|
||||||
|
|
||||||
imageDetails.slice = FIRCLSMachOSliceWithHeader((void*)mh);
|
imageDetails.slice = FIRCLSMachOSliceWithHeader((void*)mh);
|
||||||
imageDetails.vmaddr_slide = vmaddr_slide;
|
imageDetails.vmaddr_slide = vmaddr_slide;
|
||||||
FIRCLSBinaryImageFillInImageDetails(&imageDetails);
|
FIRCLSBinaryImageFillInImageDetails(&imageDetails);
|
||||||
|
|
||||||
// this is an atomic operation
|
// Do these time-consuming operations on a background queue
|
||||||
FIRCLSBinaryImageStoreNode(added, imageDetails);
|
|
||||||
|
|
||||||
// this isn't, so do it on a serial queue
|
|
||||||
dispatch_async(FIRCLSGetBinaryImageQueue(), ^{
|
dispatch_async(FIRCLSGetBinaryImageQueue(), ^{
|
||||||
|
// this is an atomic operation
|
||||||
|
FIRCLSBinaryImageStoreNode(added, imageDetails);
|
||||||
FIRCLSBinaryImageRecordSlice(added, imageDetails);
|
FIRCLSBinaryImageRecordSlice(added, imageDetails);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "FIRCLSAllocate.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h"
|
||||||
#include "FIRCLSBinaryImage.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||||
#include "FIRCLSException.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||||
#include "FIRCLSFeatures.h"
|
#include "Crashlytics/Crashlytics/Handlers/FIRCLSException.h"
|
||||||
#include "FIRCLSHost.h"
|
#include "Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h"
|
||||||
#include "FIRCLSInternalLogging.h"
|
#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h"
|
||||||
#include "FIRCLSMachException.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h"
|
||||||
#include "FIRCLSSignal.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||||
#include "FIRCLSUserLogging.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h"
|
||||||
|
|
||||||
#include <dispatch/dispatch.h>
|
#include <dispatch/dispatch.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -57,7 +57,9 @@ typedef struct {
|
||||||
FIRCLSBinaryImageReadOnlyContext binaryimage;
|
FIRCLSBinaryImageReadOnlyContext binaryimage;
|
||||||
FIRCLSExceptionReadOnlyContext exception;
|
FIRCLSExceptionReadOnlyContext exception;
|
||||||
FIRCLSHostReadOnlyContext host;
|
FIRCLSHostReadOnlyContext host;
|
||||||
|
#if CLS_SIGNAL_SUPPORTED
|
||||||
FIRCLSSignalReadContext signal;
|
FIRCLSSignalReadContext signal;
|
||||||
|
#endif
|
||||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||||
FIRCLSMachExceptionReadContext machException;
|
FIRCLSMachExceptionReadContext machException;
|
||||||
#endif
|
#endif
|
||||||
|
@ -84,7 +86,6 @@ typedef struct {
|
||||||
const char* rootPath;
|
const char* rootPath;
|
||||||
const char* previouslyCrashedFileRootPath;
|
const char* previouslyCrashedFileRootPath;
|
||||||
const char* sessionId;
|
const char* sessionId;
|
||||||
const char* installId;
|
|
||||||
const char* betaToken;
|
const char* betaToken;
|
||||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||||
exception_mask_t machExceptionMask;
|
exception_mask_t machExceptionMask;
|
||||||
|
@ -100,14 +101,8 @@ typedef struct {
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
||||||
FIRCLSSettings* settings,
|
FIRCLSSettings* settings,
|
||||||
FIRCLSInstallIdentifierModel* installIDModel,
|
|
||||||
FIRCLSFileManager* fileManager);
|
FIRCLSFileManager* fileManager);
|
||||||
|
|
||||||
// Re-writes the metadata file on the current thread
|
|
||||||
void FIRCLSContextUpdateMetadata(FIRCLSInternalReport* report,
|
|
||||||
FIRCLSSettings* settings,
|
|
||||||
FIRCLSInstallIdentifierModel* installIDModel,
|
|
||||||
FIRCLSFileManager* fileManager);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void FIRCLSContextBaseInit(void);
|
void FIRCLSContextBaseInit(void);
|
||||||
|
|
|
@ -12,23 +12,25 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSContext.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#import "FIRCLSFileManager.h"
|
#import "Crashlytics/Shared/FIRCLSConstants.h"
|
||||||
#import "FIRCLSInstallIdentifierModel.h"
|
|
||||||
#import "FIRCLSInternalReport.h"
|
|
||||||
#import "FIRCLSSettings.h"
|
|
||||||
|
|
||||||
#include "FIRCLSApplication.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||||
#include "FIRCLSCrashedMarkerFile.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||||
#include "FIRCLSDefines.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||||
#include "FIRCLSFeatures.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
|
||||||
#include "FIRCLSGlobals.h"
|
|
||||||
#include "FIRCLSProcess.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"
|
||||||
|
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
|
#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h"
|
||||||
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||||
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||||
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
// The writable size is our handler stack plus whatever scratch we need. We have to use this space
|
// The writable size is our handler stack plus whatever scratch we need. We have to use this space
|
||||||
// extremely carefully, however, because thread stacks always needs to be page-aligned. Only the
|
// extremely carefully, however, because thread stacks always needs to be page-aligned. Only the
|
||||||
|
@ -51,7 +53,6 @@ static void FIRCLSContextAllocate(FIRCLSContext* context);
|
||||||
|
|
||||||
FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
||||||
FIRCLSSettings* settings,
|
FIRCLSSettings* settings,
|
||||||
FIRCLSInstallIdentifierModel* installIDModel,
|
|
||||||
FIRCLSFileManager* fileManager) {
|
FIRCLSFileManager* fileManager) {
|
||||||
// Because we need to start the crash reporter right away,
|
// Because we need to start the crash reporter right away,
|
||||||
// it starts up either with default settings, or cached settings
|
// it starts up either with default settings, or cached settings
|
||||||
|
@ -62,7 +63,6 @@ FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
||||||
memset(&initData, 0, sizeof(FIRCLSContextInitData));
|
memset(&initData, 0, sizeof(FIRCLSContextInitData));
|
||||||
|
|
||||||
initData.customBundleId = nil;
|
initData.customBundleId = nil;
|
||||||
initData.installId = [installIDModel.installID UTF8String];
|
|
||||||
initData.sessionId = [[report identifier] UTF8String];
|
initData.sessionId = [[report identifier] UTF8String];
|
||||||
initData.rootPath = [[report path] UTF8String];
|
initData.rootPath = [[report path] UTF8String];
|
||||||
initData.previouslyCrashedFileRootPath = [[fileManager rootPath] UTF8String];
|
initData.previouslyCrashedFileRootPath = [[fileManager rootPath] UTF8String];
|
||||||
|
@ -72,6 +72,7 @@ FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
||||||
initData.maxErrorLogSize = [settings errorLogBufferSize];
|
initData.maxErrorLogSize = [settings errorLogBufferSize];
|
||||||
initData.maxLogSize = [settings logBufferSize];
|
initData.maxLogSize = [settings logBufferSize];
|
||||||
initData.maxKeyValues = [settings maxCustomKeys];
|
initData.maxKeyValues = [settings maxCustomKeys];
|
||||||
|
initData.betaToken = "";
|
||||||
|
|
||||||
// If this is set, then we could attempt to do a synchronous submission for certain kinds of
|
// If this is set, then we could attempt to do a synchronous submission for certain kinds of
|
||||||
// events (exceptions). This is a very cool feature, but adds complexity to the backend. For now,
|
// events (exceptions). This is a very cool feature, but adds complexity to the backend. For now,
|
||||||
|
@ -98,10 +99,8 @@ FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
||||||
|
|
||||||
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
||||||
FIRCLSSettings* settings,
|
FIRCLSSettings* settings,
|
||||||
FIRCLSInstallIdentifierModel* installIDModel,
|
|
||||||
FIRCLSFileManager* fileManager) {
|
FIRCLSFileManager* fileManager) {
|
||||||
FIRCLSContextInitData initDataObj =
|
FIRCLSContextInitData initDataObj = FIRCLSContextBuildInitData(report, settings, fileManager);
|
||||||
FIRCLSContextBuildInitData(report, settings, installIDModel, fileManager);
|
|
||||||
FIRCLSContextInitData* initData = &initDataObj;
|
FIRCLSContextInitData* initData = &initDataObj;
|
||||||
|
|
||||||
if (!initData) {
|
if (!initData) {
|
||||||
|
@ -194,13 +193,18 @@ bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
||||||
FIRCLSContextAppendToRoot(rootPath, fileName);
|
FIRCLSContextAppendToRoot(rootPath, fileName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// To initialize Crashlytics handlers even if the Xcode debugger is attached, replace this check
|
||||||
|
// with YES. Note that this is only possible to do on an actual device as it will cause the
|
||||||
|
// simulator to crash.
|
||||||
if (!_firclsContext.readonly->debuggerAttached) {
|
if (!_firclsContext.readonly->debuggerAttached) {
|
||||||
|
#if CLS_SIGNAL_SUPPORTED
|
||||||
dispatch_group_async(group, queue, ^{
|
dispatch_group_async(group, queue, ^{
|
||||||
_firclsContext.readonly->signal.path =
|
_firclsContext.readonly->signal.path =
|
||||||
FIRCLSContextAppendToRoot(rootPath, FIRCLSReportSignalFile);
|
FIRCLSContextAppendToRoot(rootPath, FIRCLSReportSignalFile);
|
||||||
|
|
||||||
FIRCLSSignalInitialize(&_firclsContext.readonly->signal);
|
FIRCLSSignalInitialize(&_firclsContext.readonly->signal);
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||||
dispatch_group_async(group, queue, ^{
|
dispatch_group_async(group, queue, ^{
|
||||||
|
@ -255,24 +259,6 @@ bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FIRCLSContextUpdateMetadata(FIRCLSInternalReport* report,
|
|
||||||
FIRCLSSettings* settings,
|
|
||||||
FIRCLSInstallIdentifierModel* installIDModel,
|
|
||||||
FIRCLSFileManager* fileManager) {
|
|
||||||
FIRCLSContextInitData initDataObj =
|
|
||||||
FIRCLSContextBuildInitData(report, settings, installIDModel, fileManager);
|
|
||||||
FIRCLSContextInitData* initData = &initDataObj;
|
|
||||||
|
|
||||||
NSString* rootPath = [NSString stringWithUTF8String:initData->rootPath];
|
|
||||||
|
|
||||||
const char* metaDataPath =
|
|
||||||
[[rootPath stringByAppendingPathComponent:FIRCLSReportMetadataFile] fileSystemRepresentation];
|
|
||||||
|
|
||||||
if (!FIRCLSContextRecordMetadata(metaDataPath, initData)) {
|
|
||||||
FIRCLSErrorLog(@"Unable to update context metadata");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FIRCLSContextBaseInit(void) {
|
void FIRCLSContextBaseInit(void) {
|
||||||
NSString* sdkBundleID = FIRCLSApplicationGetSDKBundleID();
|
NSString* sdkBundleID = FIRCLSApplicationGetSDKBundleID();
|
||||||
|
|
||||||
|
@ -397,13 +383,15 @@ static bool FIRCLSContextRecordIdentity(FIRCLSFile* file, const FIRCLSContextIni
|
||||||
|
|
||||||
FIRCLSFileWriteHashStart(file);
|
FIRCLSFileWriteHashStart(file);
|
||||||
|
|
||||||
FIRCLSFileWriteHashEntryString(file, "generator", CLS_SDK_GENERATOR_NAME);
|
FIRCLSFileWriteHashEntryString(file, "generator", FIRCLSSDKGeneratorName().UTF8String);
|
||||||
FIRCLSFileWriteHashEntryString(file, "display_version", CLS_SDK_DISPLAY_VERSION);
|
FIRCLSFileWriteHashEntryString(file, "display_version", FIRCLSSDKVersion().UTF8String);
|
||||||
FIRCLSFileWriteHashEntryString(file, "build_version", CLS_SDK_DISPLAY_VERSION);
|
FIRCLSFileWriteHashEntryString(file, "build_version", FIRCLSSDKVersion().UTF8String);
|
||||||
FIRCLSFileWriteHashEntryUint64(file, "started_at", time(NULL));
|
FIRCLSFileWriteHashEntryUint64(file, "started_at", time(NULL));
|
||||||
|
|
||||||
FIRCLSFileWriteHashEntryString(file, "session_id", initData->sessionId);
|
FIRCLSFileWriteHashEntryString(file, "session_id", initData->sessionId);
|
||||||
FIRCLSFileWriteHashEntryString(file, "install_id", initData->installId);
|
// install_id is written into the proto directly. This is only left here to
|
||||||
|
// support Apple Report Converter.
|
||||||
|
FIRCLSFileWriteHashEntryString(file, "install_id", "");
|
||||||
FIRCLSFileWriteHashEntryString(file, "beta_token", initData->betaToken);
|
FIRCLSFileWriteHashEntryString(file, "beta_token", initData->betaToken);
|
||||||
FIRCLSFileWriteHashEntryBoolean(file, "absolute_log_timestamps", true);
|
FIRCLSFileWriteHashEntryBoolean(file, "absolute_log_timestamps", true);
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSCrashedMarkerFile.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
const char *FIRCLSCrashedMarkerFileName = "previously-crashed";
|
const char *FIRCLSCrashedMarkerFileName = "previously-crashed";
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSContext.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <mach/vm_types.h>
|
#include <mach/vm_types.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* documentDirectoryPath;
|
const char* documentDirectoryPath;
|
||||||
|
@ -34,4 +34,6 @@ bool FIRCLSHostRecord(FIRCLSFile* file);
|
||||||
|
|
||||||
void FIRCLSHostWriteDiskUsage(FIRCLSFile* file);
|
void FIRCLSHostWriteDiskUsage(FIRCLSFile* file);
|
||||||
|
|
||||||
|
bool FIRCLSHostIsRosettaTranslated(void);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -12,18 +12,18 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSHost.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||||
|
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
#import "FIRCLSApplication.h"
|
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
#include "FIRCLSDefines.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
#import "FIRCLSFABHost.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
#include "FIRCLSGlobals.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
#include "FIRCLSUtility.h"
|
#import "Crashlytics/Shared/FIRCLSFABHost.h"
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
@ -32,9 +32,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CLS_HOST_SYSCTL_BUFFER_SIZE (128)
|
#define CLS_HOST_SYSCTL_BUFFER_SIZE (128)
|
||||||
|
#define CLS_MAX_ARM64_NATIVE_PAGE_SIZE (1024 * 16)
|
||||||
|
|
||||||
#if CLS_CPU_ARM64
|
#if CLS_CPU_ARM64
|
||||||
#define CLS_MAX_NATIVE_PAGE_SIZE (1024 * 16)
|
#define CLS_MAX_NATIVE_PAGE_SIZE CLS_MAX_ARM64_NATIVE_PAGE_SIZE
|
||||||
#else
|
#else
|
||||||
// return 4K, which is correct for all platforms except arm64, currently
|
// return 4K, which is correct for all platforms except arm64, currently
|
||||||
#define CLS_MAX_NATIVE_PAGE_SIZE (1024 * 4)
|
#define CLS_MAX_NATIVE_PAGE_SIZE (1024 * 4)
|
||||||
|
@ -68,22 +69,32 @@ vm_size_t FIRCLSHostGetPageSize(void) {
|
||||||
// these types. Turns out that sysctl will not init the data to zero, but it appears
|
// these types. Turns out that sysctl will not init the data to zero, but it appears
|
||||||
// that sysctlbyname does. This API is nicer, but that's important to keep in mind.
|
// that sysctlbyname does. This API is nicer, but that's important to keep in mind.
|
||||||
|
|
||||||
|
int maxNativePageSize = CLS_MAX_NATIVE_PAGE_SIZE;
|
||||||
|
|
||||||
|
// On Apple Silicon, we need to use the arm64 page size
|
||||||
|
// even if we're in x86 land.
|
||||||
|
if (FIRCLSHostIsRosettaTranslated()) {
|
||||||
|
FIRCLSSDKLog("Running under Rosetta 2 emulation. Using the arm64 page size.\n");
|
||||||
|
|
||||||
|
maxNativePageSize = CLS_MAX_ARM64_NATIVE_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
pageSize = 0;
|
pageSize = 0;
|
||||||
size = sizeof(pageSize);
|
size = sizeof(pageSize);
|
||||||
if (sysctlbyname("hw.pagesize", &pageSize, &size, NULL, 0) != 0) {
|
if (sysctlbyname("hw.pagesize", &pageSize, &size, NULL, 0) != 0) {
|
||||||
FIRCLSSDKLog("sysctlbyname failed while trying to get hw.pagesize\n");
|
FIRCLSSDKLog("sysctlbyname failed while trying to get hw.pagesize\n");
|
||||||
|
|
||||||
return CLS_MAX_NATIVE_PAGE_SIZE;
|
return maxNativePageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the returned size is not the expected value, abort
|
// if the returned size is not the expected value, abort
|
||||||
if (size != sizeof(pageSize)) {
|
if (size != sizeof(pageSize)) {
|
||||||
return CLS_MAX_NATIVE_PAGE_SIZE;
|
return maxNativePageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// put in some guards to make sure our size is reasonable
|
// put in some guards to make sure our size is reasonable
|
||||||
if (pageSize > CLS_MAX_NATIVE_PAGE_SIZE) {
|
if (pageSize > maxNativePageSize) {
|
||||||
return CLS_MAX_NATIVE_PAGE_SIZE;
|
return maxNativePageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pageSize < CLS_MIN_NATIVE_PAGE_SIZE) {
|
if (pageSize < CLS_MIN_NATIVE_PAGE_SIZE) {
|
||||||
|
@ -93,6 +104,29 @@ vm_size_t FIRCLSHostGetPageSize(void) {
|
||||||
return pageSize;
|
return pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This comes from the Apple documentation here:
|
||||||
|
// https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment
|
||||||
|
bool FIRCLSHostIsRosettaTranslated() {
|
||||||
|
#if TARGET_OS_MAC
|
||||||
|
int result = 0;
|
||||||
|
size_t size = sizeof(result);
|
||||||
|
if (sysctlbyname("sysctl.proc_translated", &result, &size, NULL, 0) == -1) {
|
||||||
|
// If we get an error, or 0, we're going to treat this as x86_64 macOS native
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// This is the error case
|
||||||
|
FIRCLSSDKLog("sysctlbyname failed while trying to get sysctl.proc_translated for Rosetta 2 "
|
||||||
|
"translation\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return result == 1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void FIRCLSHostWriteSysctlEntry(
|
static void FIRCLSHostWriteSysctlEntry(
|
||||||
FIRCLSFile* file, const char* key, const char* sysctlKey, void* buffer, size_t bufferSize) {
|
FIRCLSFile* file, const char* key, const char* sysctlKey, void* buffer, size_t bufferSize) {
|
||||||
if (sysctlbyname(sysctlKey, buffer, &bufferSize, NULL, 0) != 0) {
|
if (sysctlbyname(sysctlKey, buffer, &bufferSize, NULL, 0) != 0) {
|
||||||
|
@ -124,6 +158,8 @@ static void FIRCLSHostWriteOSVersionInfo(FIRCLSFile* file) {
|
||||||
FIRCLSFileWriteHashEntryString(file, "os_display_version",
|
FIRCLSFileWriteHashEntryString(file, "os_display_version",
|
||||||
[FIRCLSHostOSDisplayVersion() UTF8String]);
|
[FIRCLSHostOSDisplayVersion() UTF8String]);
|
||||||
FIRCLSFileWriteHashEntryString(file, "platform", [FIRCLSApplicationGetPlatform() UTF8String]);
|
FIRCLSFileWriteHashEntryString(file, "platform", [FIRCLSApplicationGetPlatform() UTF8String]);
|
||||||
|
FIRCLSFileWriteHashEntryString(file, "firebase_platform",
|
||||||
|
[FIRCLSApplicationGetFirebasePlatform() UTF8String]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FIRCLSHostRecord(FIRCLSFile* file) {
|
bool FIRCLSHostRecord(FIRCLSFile* file) {
|
||||||
|
|
|
@ -12,14 +12,14 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSProcess.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h"
|
||||||
#include "FIRCLSDefines.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||||
#include "FIRCLSFeatures.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||||
#include "FIRCLSGlobals.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
#include "FIRCLSProfiling.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSProfiling.h"
|
||||||
#include "FIRCLSThreadState.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h"
|
||||||
#include "FIRCLSUnwind.h"
|
#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h"
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
#include <dispatch/dispatch.h>
|
#include <dispatch/dispatch.h>
|
||||||
#include <objc/message.h>
|
#include <objc/message.h>
|
||||||
|
@ -57,10 +57,6 @@ bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uap
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FIRCLSProcessDestroy(FIRCLSProcess *process) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
|
// https://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
|
||||||
bool FIRCLSProcessDebuggerAttached(void) {
|
bool FIRCLSProcessDebuggerAttached(void) {
|
||||||
int junk;
|
int junk;
|
||||||
|
@ -167,7 +163,7 @@ static bool FIRCLSProcessGetThreadState(FIRCLSProcess *process,
|
||||||
thread_t thread,
|
thread_t thread,
|
||||||
FIRCLSThreadContext *context) {
|
FIRCLSThreadContext *context) {
|
||||||
if (!FIRCLSIsValidPointer(context)) {
|
if (!FIRCLSIsValidPointer(context)) {
|
||||||
FIRCLSSDKLogError("invalid context supplied");
|
FIRCLSSDKLogError("Invalid context supplied\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,9 +212,14 @@ static bool FIRCLSProcessGetThreadState(FIRCLSProcess *process,
|
||||||
#if !TARGET_OS_WATCH
|
#if !TARGET_OS_WATCH
|
||||||
// try to get the value by querying the thread state
|
// try to get the value by querying the thread state
|
||||||
mach_msg_type_number_t stateCount = FIRCLSThreadStateCount;
|
mach_msg_type_number_t stateCount = FIRCLSThreadStateCount;
|
||||||
if (thread_get_state(thread, FIRCLSThreadState, (thread_state_t)(&(context->__ss)),
|
|
||||||
&stateCount) != KERN_SUCCESS) {
|
// For unknown reasons, thread_get_state returns this value on Rosetta,
|
||||||
FIRCLSSDKLogError("failed to get thread state\n");
|
// but still succeeds.
|
||||||
|
const int ROSETTA_SUCCESS = 268435459;
|
||||||
|
kern_return_t status = thread_get_state(thread, FIRCLSThreadState, (thread_state_t)(&(context->__ss)),
|
||||||
|
&stateCount);
|
||||||
|
if (status != KERN_SUCCESS && status != ROSETTA_SUCCESS) {
|
||||||
|
FIRCLSSDKLogError("Failed to get thread state via thread_get_state for thread: %i\n", thread);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +255,7 @@ static const char *FIRCLSProcessGetThreadDispatchQueueName(FIRCLSProcess *proces
|
||||||
infoCount = THREAD_IDENTIFIER_INFO_COUNT;
|
infoCount = THREAD_IDENTIFIER_INFO_COUNT;
|
||||||
if (thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&info, &infoCount) !=
|
if (thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&info, &infoCount) !=
|
||||||
KERN_SUCCESS) {
|
KERN_SUCCESS) {
|
||||||
FIRCLSSDKLog("unable to get thread info\n");
|
FIRCLSSDKLog("Unable to get thread info\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,12 +391,12 @@ static bool FIRCLSProcessRecordThread(FIRCLSProcess *process, thread_t thread, F
|
||||||
FIRCLSThreadContext context;
|
FIRCLSThreadContext context;
|
||||||
|
|
||||||
if (!FIRCLSProcessGetThreadState(process, thread, &context)) {
|
if (!FIRCLSProcessGetThreadState(process, thread, &context)) {
|
||||||
FIRCLSSDKLogError("unable to get thread state");
|
FIRCLSSDKLogError("Unable to get thread state\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FIRCLSUnwindInit(&unwindContext, context)) {
|
if (!FIRCLSUnwindInit(&unwindContext, context)) {
|
||||||
FIRCLSSDKLog("unable to init unwind context\n");
|
FIRCLSSDKLog("Unable to init unwind context\n");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -485,6 +486,11 @@ bool FIRCLSProcessRecordAllThreads(FIRCLSProcess *process, FIRCLSFile *file) {
|
||||||
|
|
||||||
FIRCLSSDKLogInfo("recording thread %d data\n", i);
|
FIRCLSSDKLogInfo("recording thread %d data\n", i);
|
||||||
if (!FIRCLSProcessRecordThread(process, thread, file)) {
|
if (!FIRCLSProcessRecordThread(process, thread, file)) {
|
||||||
|
FIRCLSSDKLogError("Failed to record thread state. Closing threads JSON to prevent malformed crash report.\n");
|
||||||
|
|
||||||
|
FIRCLSFileWriteArrayEnd(file);
|
||||||
|
|
||||||
|
FIRCLSFileWriteSectionEnd(file);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,7 +499,7 @@ bool FIRCLSProcessRecordAllThreads(FIRCLSProcess *process, FIRCLSFile *file) {
|
||||||
|
|
||||||
FIRCLSFileWriteSectionEnd(file);
|
FIRCLSFileWriteSectionEnd(file);
|
||||||
|
|
||||||
FIRCLSSDKLogInfo("completed recording all thread data\n");
|
FIRCLSSDKLogInfo("Completed recording all thread data\n");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -541,6 +547,11 @@ void FIRCLSProcessRecordDispatchQueueNames(FIRCLSProcess *process, FIRCLSFile *f
|
||||||
|
|
||||||
name = FIRCLSProcessGetThreadDispatchQueueName(process, thread);
|
name = FIRCLSProcessGetThreadDispatchQueueName(process, thread);
|
||||||
|
|
||||||
|
// Apple Report Converter will fail to parse this when "name" is null,
|
||||||
|
// so we will use an empty string instead.
|
||||||
|
if (name == NULL) {
|
||||||
|
name = "";
|
||||||
|
}
|
||||||
FIRCLSFileWriteArrayEntryString(file, name);
|
FIRCLSFileWriteArrayEntryString(file, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,6 +806,12 @@ static void FIRCLSProcessRecordCrashInfo(FIRCLSFile *file) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The crash_info_t's message may contain the device's UDID, in this case,
|
||||||
|
// make sure that we do our best to redact that information before writing the
|
||||||
|
// rest of the message to disk. This also has the effect of not uploading that
|
||||||
|
// information in the subsequent crash report.
|
||||||
|
FIRCLSRedactUUID(string);
|
||||||
|
|
||||||
FIRCLSFileWriteArrayEntryHexEncodedString(file, string);
|
FIRCLSFileWriteArrayEntryHexEncodedString(file, string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// task info
|
// task info
|
||||||
|
@ -32,7 +32,6 @@ typedef struct {
|
||||||
} FIRCLSProcess;
|
} FIRCLSProcess;
|
||||||
|
|
||||||
bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uapVoid);
|
bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uapVoid);
|
||||||
bool FIRCLSProcessDestroy(FIRCLSProcess *process);
|
|
||||||
bool FIRCLSProcessDebuggerAttached(void);
|
bool FIRCLSProcessDebuggerAttached(void);
|
||||||
|
|
||||||
bool FIRCLSProcessSuspendAllOtherThreads(FIRCLSProcess *process);
|
bool FIRCLSProcessSuspendAllOtherThreads(FIRCLSProcess *process);
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "FIRCLSFile.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext* roContext,
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
void FIRCLSUserLoggingRecordUserKeyValue(NSString* key, id value);
|
void FIRCLSUserLoggingRecordUserKeyValue(NSString* key, id value);
|
||||||
|
void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary* keysAndValues);
|
||||||
void FIRCLSUserLoggingRecordInternalKeyValue(NSString* key, id value);
|
void FIRCLSUserLoggingRecordInternalKeyValue(NSString* key, id value);
|
||||||
void FIRCLSUserLoggingWriteInternalKeyValue(NSString* key, NSString* value);
|
void FIRCLSUserLoggingWriteInternalKeyValue(NSString* key, NSString* value);
|
||||||
|
|
||||||
|
@ -89,6 +90,10 @@ void FIRCLSUserLoggingRecordKeyValue(NSString* key,
|
||||||
FIRCLSUserLoggingKVStorage* storage,
|
FIRCLSUserLoggingKVStorage* storage,
|
||||||
uint32_t* counter);
|
uint32_t* counter);
|
||||||
|
|
||||||
|
void FIRCLSUserLoggingRecordKeysAndValues(NSDictionary* keysAndValues,
|
||||||
|
FIRCLSUserLoggingKVStorage* storage,
|
||||||
|
uint32_t* counter);
|
||||||
|
|
||||||
void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage* storage,
|
void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage* storage,
|
||||||
const char** activePath,
|
const char** activePath,
|
||||||
void (^openedFileBlock)(FIRCLSFile* file));
|
void (^openedFileBlock)(FIRCLSFile* file));
|
||||||
|
@ -96,6 +101,11 @@ void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage* storage,
|
||||||
NSArray* FIRCLSUserLoggingStoredKeyValues(const char* path);
|
NSArray* FIRCLSUserLoggingStoredKeyValues(const char* path);
|
||||||
|
|
||||||
OBJC_EXTERN void FIRCLSLog(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2);
|
OBJC_EXTERN void FIRCLSLog(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2);
|
||||||
|
OBJC_EXTERN void FIRCLSLogToStorage(FIRCLSUserLoggingABStorage* storage,
|
||||||
|
const char** activePath,
|
||||||
|
NSString* format,
|
||||||
|
...) NS_FORMAT_FUNCTION(3, 4);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -12,14 +12,14 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FIRCLSUserLogging.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "FIRCLSGlobals.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
#import "FIRCLSReportManager_Private.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h"
|
||||||
|
|
||||||
NSString *const FIRCLSStartTimeKey = @"com.crashlytics.kit-start-time";
|
NSString *const FIRCLSStartTimeKey = @"com.crashlytics.kit-start-time";
|
||||||
NSString *const FIRCLSFirstRunloopTurnTimeKey = @"com.crashlytics.first-run-loop-time";
|
NSString *const FIRCLSFirstRunloopTurnTimeKey = @"com.crashlytics.first-run-loop-time";
|
||||||
|
@ -33,17 +33,21 @@ NSString *const FIRCLSDevelopmentPlatformNameKey = @"com.crashlytics.development
|
||||||
NSString *const FIRCLSDevelopmentPlatformVersionKey =
|
NSString *const FIRCLSDevelopmentPlatformVersionKey =
|
||||||
@"com.crashlytics.development-platform-version";
|
@"com.crashlytics.development-platform-version";
|
||||||
|
|
||||||
|
// Empty string object synchronized on to prevent a race condition when accessing AB file path
|
||||||
|
NSString *const FIRCLSSynchronizedPathKey = @"";
|
||||||
|
|
||||||
const uint32_t FIRCLSUserLoggingMaxKVEntries = 64;
|
const uint32_t FIRCLSUserLoggingMaxKVEntries = 64;
|
||||||
|
|
||||||
#pragma mark - Prototypes
|
#pragma mark - Prototypes
|
||||||
static void FIRCLSUserLoggingWriteKeyValue(NSString *key,
|
static void FIRCLSUserLoggingWriteKeysAndValues(NSDictionary *keysAndValues,
|
||||||
NSString *value,
|
FIRCLSUserLoggingKVStorage *storage,
|
||||||
FIRCLSUserLoggingKVStorage *storage,
|
uint32_t *counter);
|
||||||
uint32_t *counter);
|
|
||||||
static void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage,
|
static void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage,
|
||||||
const char **activePath,
|
const char **activePath,
|
||||||
off_t fileSize);
|
off_t fileSize);
|
||||||
void FIRCLSLogInternal(NSString *message);
|
void FIRCLSLogInternal(FIRCLSUserLoggingABStorage *storage,
|
||||||
|
const char **activePath,
|
||||||
|
NSString *message);
|
||||||
|
|
||||||
#pragma mark - Setup
|
#pragma mark - Setup
|
||||||
void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext *roContext,
|
void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext *roContext,
|
||||||
|
@ -68,8 +72,10 @@ void FIRCLSUserLoggingRecordInternalKeyValue(NSString *key, id value) {
|
||||||
|
|
||||||
void FIRCLSUserLoggingWriteInternalKeyValue(NSString *key, NSString *value) {
|
void FIRCLSUserLoggingWriteInternalKeyValue(NSString *key, NSString *value) {
|
||||||
// Unsynchronized - must be run on the correct queue
|
// Unsynchronized - must be run on the correct queue
|
||||||
FIRCLSUserLoggingWriteKeyValue(key, value, &_firclsContext.readonly->logging.internalKVStorage,
|
NSDictionary *keysAndValues = key ? @{key : value ?: [NSNull null]} : nil;
|
||||||
&_firclsContext.writable->logging.internalKVCount);
|
FIRCLSUserLoggingWriteKeysAndValues(keysAndValues,
|
||||||
|
&_firclsContext.readonly->logging.internalKVStorage,
|
||||||
|
&_firclsContext.writable->logging.internalKVCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FIRCLSUserLoggingRecordUserKeyValue(NSString *key, id value) {
|
void FIRCLSUserLoggingRecordUserKeyValue(NSString *key, id value) {
|
||||||
|
@ -77,6 +83,12 @@ void FIRCLSUserLoggingRecordUserKeyValue(NSString *key, id value) {
|
||||||
&_firclsContext.writable->logging.userKVCount);
|
&_firclsContext.writable->logging.userKVCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary *keysAndValues) {
|
||||||
|
FIRCLSUserLoggingRecordKeysAndValues(keysAndValues,
|
||||||
|
&_firclsContext.readonly->logging.userKVStorage,
|
||||||
|
&_firclsContext.writable->logging.userKVCount);
|
||||||
|
}
|
||||||
|
|
||||||
static id FIRCLSUserLoggingGetComponent(NSDictionary *entry,
|
static id FIRCLSUserLoggingGetComponent(NSDictionary *entry,
|
||||||
NSString *componentName,
|
NSString *componentName,
|
||||||
bool decodeHex) {
|
bool decodeHex) {
|
||||||
|
@ -140,6 +152,30 @@ NSDictionary *FIRCLSUserLoggingGetCompactedKVEntries(FIRCLSUserLoggingKVStorage
|
||||||
return finalKVSet;
|
return finalKVSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FIRCLSUserLoggingWriteKVEntriesToFile(
|
||||||
|
NSDictionary<NSString *, NSString *> *keysAndValues, BOOL shouldHexEncode, FIRCLSFile *file) {
|
||||||
|
for (NSString *key in keysAndValues) {
|
||||||
|
NSString *valueObject = [keysAndValues objectForKey:key];
|
||||||
|
|
||||||
|
// map `NSNull` into nil
|
||||||
|
const char *value = (valueObject == (NSString *)[NSNull null] ? nil : [valueObject UTF8String]);
|
||||||
|
|
||||||
|
FIRCLSFileWriteSectionStart(file, "kv");
|
||||||
|
FIRCLSFileWriteHashStart(file);
|
||||||
|
|
||||||
|
if (shouldHexEncode) {
|
||||||
|
FIRCLSFileWriteHashEntryHexEncodedString(file, "key", [key UTF8String]);
|
||||||
|
FIRCLSFileWriteHashEntryHexEncodedString(file, "value", value);
|
||||||
|
} else {
|
||||||
|
FIRCLSFileWriteHashEntryString(file, "key", [key UTF8String]);
|
||||||
|
FIRCLSFileWriteHashEntryString(file, "value", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRCLSFileWriteHashEnd(file);
|
||||||
|
FIRCLSFileWriteSectionEnd(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FIRCLSUserLoggingCompactKVEntries(FIRCLSUserLoggingKVStorage *storage) {
|
void FIRCLSUserLoggingCompactKVEntries(FIRCLSUserLoggingKVStorage *storage) {
|
||||||
if (!FIRCLSIsValidPointer(storage)) {
|
if (!FIRCLSIsValidPointer(storage)) {
|
||||||
FIRCLSSDKLogError("Error: storage invalid\n");
|
FIRCLSSDKLogError("Error: storage invalid\n");
|
||||||
|
@ -167,24 +203,14 @@ void FIRCLSUserLoggingCompactKVEntries(FIRCLSUserLoggingKVStorage *storage) {
|
||||||
// but it's very uncommon to go down this path.
|
// but it's very uncommon to go down this path.
|
||||||
NSArray *keys = [finalKVs allKeys];
|
NSArray *keys = [finalKVs allKeys];
|
||||||
|
|
||||||
FIRCLSSDKLogInfo("Truncating KV set, which is above max %d\n", maxCount);
|
FIRCLSSDKLogInfo("Truncating %d keys from KV set, which is above max %d\n",
|
||||||
|
(uint32_t)(finalKVs.count - maxCount), maxCount);
|
||||||
|
|
||||||
finalKVs =
|
finalKVs =
|
||||||
[finalKVs dictionaryWithValuesForKeys:[keys subarrayWithRange:NSMakeRange(0, maxCount)]];
|
[finalKVs dictionaryWithValuesForKeys:[keys subarrayWithRange:NSMakeRange(0, maxCount)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NSString *key in finalKVs) {
|
FIRCLSUserLoggingWriteKVEntriesToFile(finalKVs, false, &file);
|
||||||
NSString *value = [finalKVs objectForKey:key];
|
|
||||||
|
|
||||||
FIRCLSFileWriteSectionStart(&file, "kv");
|
|
||||||
FIRCLSFileWriteHashStart(&file);
|
|
||||||
// tricky - the values stored incrementally have already been hex-encoded
|
|
||||||
FIRCLSFileWriteHashEntryString(&file, "key", [key UTF8String]);
|
|
||||||
FIRCLSFileWriteHashEntryString(&file, "value", [value UTF8String]);
|
|
||||||
FIRCLSFileWriteHashEnd(&file);
|
|
||||||
FIRCLSFileWriteSectionEnd(&file);
|
|
||||||
}
|
|
||||||
|
|
||||||
FIRCLSFileClose(&file);
|
FIRCLSFileClose(&file);
|
||||||
|
|
||||||
if (unlink(storage->incrementalPath) != 0) {
|
if (unlink(storage->incrementalPath) != 0) {
|
||||||
|
@ -202,33 +228,59 @@ void FIRCLSUserLoggingRecordKeyValue(NSString *key,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure that any invalid pointer is actually set to nil
|
NSDictionary *keysAndValues = @{key : (value ?: [NSNull null])};
|
||||||
if (!FIRCLSIsValidPointer(value) && value != nil) {
|
FIRCLSUserLoggingRecordKeysAndValues(keysAndValues, storage, counter);
|
||||||
FIRCLSSDKLogWarn("Bad value pointer being clamped to nil\n");
|
}
|
||||||
value = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void FIRCLSUserLoggingRecordKeysAndValues(NSDictionary *keysAndValues,
|
||||||
|
FIRCLSUserLoggingKVStorage *storage,
|
||||||
|
uint32_t *counter) {
|
||||||
if (!FIRCLSContextIsInitialized()) {
|
if (!FIRCLSContextIsInitialized()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([value respondsToSelector:@selector(description)]) {
|
if (keysAndValues.count == 0) {
|
||||||
value = [value description];
|
FIRCLSSDKLogWarn("User provided empty key/value dictionary\n");
|
||||||
} else {
|
return;
|
||||||
// passing nil will result in a JSON null being written, which is deserialized as [NSNull null],
|
}
|
||||||
// signaling to remove the key during compaction
|
|
||||||
value = nil;
|
if (!FIRCLSIsValidPointer(keysAndValues)) {
|
||||||
|
FIRCLSSDKLogWarn("User provided bad key/value dictionary\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *sanitizedKeysAndValues = [keysAndValues mutableCopy];
|
||||||
|
for (NSString *key in keysAndValues) {
|
||||||
|
if (!FIRCLSIsValidPointer(key)) {
|
||||||
|
FIRCLSSDKLogWarn("User provided bad key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id value = keysAndValues[key];
|
||||||
|
|
||||||
|
// ensure that any invalid pointer is actually set to nil
|
||||||
|
if (!FIRCLSIsValidPointer(value) && value != nil) {
|
||||||
|
FIRCLSSDKLogWarn("Bad value pointer being clamped to nil\n");
|
||||||
|
sanitizedKeysAndValues[key] = [NSNull null];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([value respondsToSelector:@selector(description)]) {
|
||||||
|
sanitizedKeysAndValues[key] = [value description];
|
||||||
|
} else {
|
||||||
|
// passing nil will result in a JSON null being written, which is deserialized as [NSNull
|
||||||
|
// null], signaling to remove the key during compaction
|
||||||
|
sanitizedKeysAndValues[key] = [NSNull null];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_sync(FIRCLSGetLoggingQueue(), ^{
|
dispatch_sync(FIRCLSGetLoggingQueue(), ^{
|
||||||
FIRCLSUserLoggingWriteKeyValue(key, value, storage, counter);
|
FIRCLSUserLoggingWriteKeysAndValues(sanitizedKeysAndValues, storage, counter);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FIRCLSUserLoggingWriteKeyValue(NSString *key,
|
static void FIRCLSUserLoggingWriteKeysAndValues(NSDictionary *keysAndValues,
|
||||||
NSString *value,
|
FIRCLSUserLoggingKVStorage *storage,
|
||||||
FIRCLSUserLoggingKVStorage *storage,
|
uint32_t *counter) {
|
||||||
uint32_t *counter) {
|
|
||||||
FIRCLSFile file;
|
FIRCLSFile file;
|
||||||
|
|
||||||
if (!FIRCLSIsValidPointer(storage) || !FIRCLSIsValidPointer(counter)) {
|
if (!FIRCLSIsValidPointer(storage) || !FIRCLSIsValidPointer(counter)) {
|
||||||
|
@ -241,16 +293,10 @@ static void FIRCLSUserLoggingWriteKeyValue(NSString *key,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FIRCLSFileWriteSectionStart(&file, "kv");
|
FIRCLSUserLoggingWriteKVEntriesToFile(keysAndValues, true, &file);
|
||||||
FIRCLSFileWriteHashStart(&file);
|
|
||||||
FIRCLSFileWriteHashEntryHexEncodedString(&file, "key", [key UTF8String]);
|
|
||||||
FIRCLSFileWriteHashEntryHexEncodedString(&file, "value", [value UTF8String]);
|
|
||||||
FIRCLSFileWriteHashEnd(&file);
|
|
||||||
FIRCLSFileWriteSectionEnd(&file);
|
|
||||||
|
|
||||||
FIRCLSFileClose(&file);
|
FIRCLSFileClose(&file);
|
||||||
|
|
||||||
*counter += 1;
|
*counter += keysAndValues.count;
|
||||||
if (*counter >= storage->maxIncrementalCount) {
|
if (*counter >= storage->maxIncrementalCount) {
|
||||||
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
||||||
FIRCLSUserLoggingCompactKVEntries(storage);
|
FIRCLSUserLoggingCompactKVEntries(storage);
|
||||||
|
@ -356,7 +402,26 @@ void FIRCLSLog(NSString *format, ...) {
|
||||||
NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
|
NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
FIRCLSLogInternal(msg);
|
FIRCLSUserLoggingABStorage *currentStorage = &_firclsContext.readonly->logging.logStorage;
|
||||||
|
const char **activePath = &_firclsContext.writable->logging.activeUserLogPath;
|
||||||
|
FIRCLSLogInternal(currentStorage, activePath, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FIRCLSLogToStorage(FIRCLSUserLoggingABStorage *storage,
|
||||||
|
const char **activePath,
|
||||||
|
NSString *format,
|
||||||
|
...) {
|
||||||
|
// If the format is nil do nothing just like NSLog.
|
||||||
|
if (!format) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
FIRCLSLogInternal(storage, activePath, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Properties
|
#pragma mark - Properties
|
||||||
|
@ -426,7 +491,9 @@ void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage,
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:pathString error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:pathString error:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
*activePath = otherPath;
|
@synchronized(FIRCLSSynchronizedPathKey) {
|
||||||
|
*activePath = otherPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage *storage,
|
void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage *storage,
|
||||||
|
@ -436,8 +503,10 @@ void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage *storage,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*activePath) {
|
@synchronized(FIRCLSSynchronizedPathKey) {
|
||||||
return;
|
if (!*activePath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storage->restrictBySize) {
|
if (storage->restrictBySize) {
|
||||||
|
@ -484,7 +553,9 @@ void FIRCLSLogInternalWrite(FIRCLSFile *file, NSString *message, uint64_t time)
|
||||||
FIRCLSFileWriteSectionEnd(file);
|
FIRCLSFileWriteSectionEnd(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FIRCLSLogInternal(NSString *message) {
|
void FIRCLSLogInternal(FIRCLSUserLoggingABStorage *storage,
|
||||||
|
const char **activePath,
|
||||||
|
NSString *message) {
|
||||||
if (!message) {
|
if (!message) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -498,7 +569,7 @@ void FIRCLSLogInternal(NSString *message) {
|
||||||
struct timeval te;
|
struct timeval te;
|
||||||
|
|
||||||
NSUInteger messageLength = [message length];
|
NSUInteger messageLength = [message length];
|
||||||
int maxLogSize = _firclsContext.readonly->logging.logStorage.maxSize;
|
int maxLogSize = storage->maxSize;
|
||||||
|
|
||||||
if (messageLength > maxLogSize) {
|
if (messageLength > maxLogSize) {
|
||||||
FIRCLSWarningLog(
|
FIRCLSWarningLog(
|
||||||
|
@ -515,9 +586,7 @@ void FIRCLSLogInternal(NSString *message) {
|
||||||
|
|
||||||
const uint64_t time = te.tv_sec * 1000LL + te.tv_usec / 1000;
|
const uint64_t time = te.tv_sec * 1000LL + te.tv_usec / 1000;
|
||||||
|
|
||||||
FIRCLSUserLoggingWriteAndCheckABFiles(&_firclsContext.readonly->logging.logStorage,
|
FIRCLSUserLoggingWriteAndCheckABFiles(storage, activePath, ^(FIRCLSFile *file) {
|
||||||
&_firclsContext.writable->logging.activeUserLogPath,
|
FIRCLSLogInternalWrite(file, message, time);
|
||||||
^(FIRCLSFile *file) {
|
});
|
||||||
FIRCLSLogInternalWrite(file, message, time);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
55
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h
generated
Normal file
55
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h
generated
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class FIRCLSSettings;
|
||||||
|
@protocol FIRAnalyticsInterop;
|
||||||
|
@protocol FIRAnalyticsInteropListener;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registers a listener for Analytics events in Crashlytics
|
||||||
|
* logs (aka. breadcrumbs), and sends events to the
|
||||||
|
* Analytics SDK for Crash Free Users.
|
||||||
|
*/
|
||||||
|
@interface FIRCLSAnalyticsManager : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithAnalytics:(nullable id<FIRAnalyticsInterop>)analytics;
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Starts listening for Analytics events for Breadcrumbs.
|
||||||
|
*/
|
||||||
|
- (void)registerAnalyticsListener;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Logs a Crashlytics crash session to Firebase Analytics for Crash Free Users.
|
||||||
|
* @param crashTimeStamp The time stamp of the crash to be logged.
|
||||||
|
*/
|
||||||
|
+ (void)logCrashWithTimeStamp:(NSTimeInterval)crashTimeStamp
|
||||||
|
toAnalytics:(id<FIRAnalyticsInterop>)analytics;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Public for testing.
|
||||||
|
*/
|
||||||
|
NSString *FIRCLSFIRAEventDictionaryToJSON(NSDictionary *eventAsDictionary);
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
135
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.m
generated
Normal file
135
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.m
generated
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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 "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
|
||||||
|
|
||||||
|
#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h"
|
||||||
|
|
||||||
|
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
||||||
|
#import "Interop/Analytics/Public/FIRAnalyticsInteropListener.h"
|
||||||
|
|
||||||
|
static NSString *FIRCLSFirebaseAnalyticsEventLogFormat = @"$A$:%@";
|
||||||
|
|
||||||
|
// Origin for events and user properties generated by Crashlytics.
|
||||||
|
static NSString *const kFIREventOriginCrash = @"clx";
|
||||||
|
|
||||||
|
// App exception event name.
|
||||||
|
static NSString *const kFIREventAppException = @"_ae";
|
||||||
|
|
||||||
|
// Timestamp key for the event payload.
|
||||||
|
static NSString *const kFIRParameterTimestamp = @"timestamp";
|
||||||
|
|
||||||
|
// Fatal key for the event payload.
|
||||||
|
static NSString *const kFIRParameterFatal = @"fatal";
|
||||||
|
|
||||||
|
FOUNDATION_STATIC_INLINE NSNumber *timeIntervalInMillis(NSTimeInterval timeInterval) {
|
||||||
|
return @(llrint(timeInterval * 1000.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface FIRCLSAnalyticsManager () <FIRAnalyticsInteropListener>
|
||||||
|
|
||||||
|
@property(nonatomic, strong) id<FIRAnalyticsInterop> analytics;
|
||||||
|
|
||||||
|
@property(nonatomic, assign) BOOL registeredAnalyticsEventListener;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FIRCLSAnalyticsManager
|
||||||
|
|
||||||
|
- (instancetype)initWithAnalytics:(nullable id<FIRAnalyticsInterop>)analytics {
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_analytics = analytics;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerAnalyticsListener {
|
||||||
|
if (self.registeredAnalyticsEventListener) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.analytics == nil) {
|
||||||
|
FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports:Event",
|
||||||
|
"Firebase Analytics SDK not detected. Crash-free statistics and "
|
||||||
|
"breadcrumbs will not be reported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.analytics registerAnalyticsListener:self withOrigin:kFIREventOriginCrash];
|
||||||
|
|
||||||
|
FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports:Event",
|
||||||
|
"Registered Firebase Analytics event listener to receive breadcrumb logs");
|
||||||
|
|
||||||
|
self.registeredAnalyticsEventListener = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters {
|
||||||
|
NSDictionary *event = @{
|
||||||
|
@"name" : name,
|
||||||
|
@"parameters" : parameters,
|
||||||
|
};
|
||||||
|
NSString *json = FIRCLSFIRAEventDictionaryToJSON(event);
|
||||||
|
if (json != nil) {
|
||||||
|
FIRCLSLog(FIRCLSFirebaseAnalyticsEventLogFormat, json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logCrashWithTimeStamp:(NSTimeInterval)crashTimeStamp
|
||||||
|
toAnalytics:(id<FIRAnalyticsInterop>)analytics {
|
||||||
|
if (analytics == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports:Event",
|
||||||
|
"Sending app_exception event to Firebase Analytics for crash-free statistics");
|
||||||
|
|
||||||
|
NSDictionary *params = @{
|
||||||
|
kFIRParameterTimestamp : timeIntervalInMillis(crashTimeStamp),
|
||||||
|
kFIRParameterFatal : @(INT64_C(1))
|
||||||
|
};
|
||||||
|
|
||||||
|
[analytics logEventWithOrigin:kFIREventOriginCrash name:kFIREventAppException parameters:params];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *FIRCLSFIRAEventDictionaryToJSON(NSDictionary *eventAsDictionary) {
|
||||||
|
NSError *error = nil;
|
||||||
|
|
||||||
|
if (eventAsDictionary == nil) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![NSJSONSerialization isValidJSONObject:eventAsDictionary]) {
|
||||||
|
FIRCLSSDKLog("Firebase Analytics event is not valid JSON");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:eventAsDictionary
|
||||||
|
options:0
|
||||||
|
error:&error];
|
||||||
|
|
||||||
|
if (error == nil) {
|
||||||
|
NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||||
|
return json;
|
||||||
|
} else {
|
||||||
|
FIRCLSSDKLog("Unable to convert Firebase Analytics event to json");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
83
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h
generated
Normal file
83
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h
generated
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class FIRCLSManagerData;
|
||||||
|
@class FIRCLSReportUploader;
|
||||||
|
@class FIRCLSDataCollectionToken;
|
||||||
|
@class FIRCrashlyticsReport;
|
||||||
|
|
||||||
|
FOUNDATION_EXPORT NSUInteger const FIRCLSMaxUnsentReports;
|
||||||
|
|
||||||
|
@interface FIRCLSExistingReportManager : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of unsent reports on the device, ignoring empty reports in
|
||||||
|
* the active folder, and ignoring any reports in "processing" or "prepared".
|
||||||
|
*
|
||||||
|
* In the past, this would count reports in the processed or prepared
|
||||||
|
* folders. This has been changed because reports in those paths have already
|
||||||
|
* been cleared for upload, so there isn't any point in asking for permission
|
||||||
|
* or possibly spamming end-users if a report gets stuck.
|
||||||
|
*
|
||||||
|
* The tricky part is, customers will NOT be alerted in checkForUnsentReports
|
||||||
|
* for reports in these paths, but when they choose sendUnsentReports / enable data
|
||||||
|
* collection, reports in those directories will be re-managed. This should be ok and
|
||||||
|
* just an edge case because reports should only be in processing or prepared for a split second as
|
||||||
|
* they do on-device symbolication and get converted into a GDTEvent. After a report is handed off
|
||||||
|
* to GoogleDataTransport, it is uploaded regardless of Crashlytics data collection.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSUInteger unsentReportsCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value needs to stay in sync with numUnsentReports, so if there is > 0 numUnsentReports,
|
||||||
|
* newestUnsentReport needs to return a value. Otherwise it needs to return null.
|
||||||
|
*
|
||||||
|
* FIRCLSContext needs to be initialized before the FIRCrashlyticsReport is instantiated.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) FIRCrashlyticsReport *_Nullable newestUnsentReport;
|
||||||
|
|
||||||
|
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
|
||||||
|
reportUploader:(FIRCLSReportUploader *)reportUploader;
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is important to call once, early in startup, before the
|
||||||
|
* new report for this run of the app has been created. Any
|
||||||
|
* reports in ExistingReportManager will be uploaded or deleted
|
||||||
|
* and we don't want to do that for the current run of the app.
|
||||||
|
*
|
||||||
|
* If there are over MAX_UNSENT_REPORTS valid reports, this will delete them.
|
||||||
|
*
|
||||||
|
* This methods is slow and should be called only once.
|
||||||
|
*/
|
||||||
|
- (void)collectExistingReports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the side-effect of calling deleteUnsentReports, or collect_reports setting
|
||||||
|
* being false.
|
||||||
|
*/
|
||||||
|
- (void)deleteUnsentReports;
|
||||||
|
|
||||||
|
- (void)sendUnsentReportsWithToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
|
asUrgent:(BOOL)urgent;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
225
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.m
generated
Normal file
225
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.m
generated
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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 "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h"
|
||||||
|
|
||||||
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
|
||||||
|
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h"
|
||||||
|
|
||||||
|
// This value should stay in sync with the Android SDK
|
||||||
|
NSUInteger const FIRCLSMaxUnsentReports = 4;
|
||||||
|
|
||||||
|
@interface FIRCLSExistingReportManager ()
|
||||||
|
|
||||||
|
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
|
||||||
|
@property(nonatomic, strong) FIRCLSReportUploader *reportUploader;
|
||||||
|
@property(nonatomic, strong) NSOperationQueue *operationQueue;
|
||||||
|
|
||||||
|
// This list of active reports excludes the brand new active report that will be created this run of
|
||||||
|
// the app.
|
||||||
|
@property(nonatomic, strong) NSArray *existingUnemptyActiveReportPaths;
|
||||||
|
@property(nonatomic, strong) NSArray *processingReportPaths;
|
||||||
|
@property(nonatomic, strong) NSArray *preparedReportPaths;
|
||||||
|
|
||||||
|
@property(nonatomic, strong) FIRCLSInternalReport *newestInternalReport;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FIRCLSExistingReportManager
|
||||||
|
|
||||||
|
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
|
||||||
|
reportUploader:(FIRCLSReportUploader *)reportUploader {
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fileManager = managerData.fileManager;
|
||||||
|
_operationQueue = managerData.operationQueue;
|
||||||
|
_reportUploader = reportUploader;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSInteger compareNewer(FIRCLSInternalReport *reportA,
|
||||||
|
FIRCLSInternalReport *reportB,
|
||||||
|
void *context) {
|
||||||
|
// Compare naturally sorts with oldest first, so swap A and B
|
||||||
|
return [reportB.dateCreated compare:reportA.dateCreated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)collectExistingReports {
|
||||||
|
self.existingUnemptyActiveReportPaths =
|
||||||
|
[self getUnsentActiveReportsAndDeleteEmptyOrOld:self.fileManager.activePathContents];
|
||||||
|
self.processingReportPaths = self.fileManager.processingPathContents;
|
||||||
|
self.preparedReportPaths = self.fileManager.preparedPathContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (FIRCrashlyticsReport *)newestUnsentReport {
|
||||||
|
if (self.unsentReportsCount <= 0) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [[FIRCrashlyticsReport alloc] initWithInternalReport:self.newestInternalReport];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)unsentReportsCount {
|
||||||
|
// There are nuances about why we only count active reports.
|
||||||
|
// See the header comment for more information.
|
||||||
|
return self.existingUnemptyActiveReportPaths.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This has the side effect of deleting any reports over the max, starting with oldest reports.
|
||||||
|
*/
|
||||||
|
- (NSArray<NSString *> *)getUnsentActiveReportsAndDeleteEmptyOrOld:(NSArray *)reportPaths {
|
||||||
|
NSMutableArray<FIRCLSInternalReport *> *validReports = [NSMutableArray array];
|
||||||
|
for (NSString *path in reportPaths) {
|
||||||
|
FIRCLSInternalReport *_Nullable report = [FIRCLSInternalReport reportWithPath:path];
|
||||||
|
if (!report) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete reports without any crashes or non-fatals
|
||||||
|
if (![report hasAnyEvents]) {
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
[self.fileManager removeItemAtPath:path];
|
||||||
|
}];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[validReports addObject:report];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validReports.count == 0) {
|
||||||
|
return @[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort with the newest at the end
|
||||||
|
[validReports sortUsingFunction:compareNewer context:nil];
|
||||||
|
|
||||||
|
// Set our report for updating in checkAndUpdateUnsentReports
|
||||||
|
self.newestInternalReport = [validReports firstObject];
|
||||||
|
|
||||||
|
// Delete any reports above the limit, starting with the oldest
|
||||||
|
// which should be at the start of the array.
|
||||||
|
if (validReports.count > FIRCLSMaxUnsentReports) {
|
||||||
|
NSUInteger deletingCount = validReports.count - FIRCLSMaxUnsentReports;
|
||||||
|
FIRCLSInfoLog(@"Deleting %lu unsent reports over the limit of %lu to prevent disk space from "
|
||||||
|
@"filling up. To prevent this make sure to call send/deleteUnsentReports.",
|
||||||
|
deletingCount, FIRCLSMaxUnsentReports);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not that validReports is sorted, delete any reports at indices > MAX_UNSENT_REPORTS, and
|
||||||
|
// collect the rest of the reports to return.
|
||||||
|
NSMutableArray<NSString *> *validReportPaths = [NSMutableArray array];
|
||||||
|
for (int i = 0; i < validReports.count; i++) {
|
||||||
|
if (i >= FIRCLSMaxUnsentReports) {
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
NSString *path = [[validReports objectAtIndex:i] path];
|
||||||
|
[self.fileManager removeItemAtPath:path];
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
[validReportPaths addObject:[[validReports objectAtIndex:i] path]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validReportPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendUnsentReportsWithToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
|
asUrgent:(BOOL)urgent {
|
||||||
|
for (NSString *path in self.existingUnemptyActiveReportPaths) {
|
||||||
|
[self processExistingActiveReportPath:path
|
||||||
|
dataCollectionToken:dataCollectionToken
|
||||||
|
asUrgent:urgent];
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with stuff in processing more carefully - do not process again
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
for (NSString *path in self.processingReportPaths) {
|
||||||
|
FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
|
||||||
|
[self.reportUploader prepareAndSubmitReport:report
|
||||||
|
dataCollectionToken:dataCollectionToken
|
||||||
|
asUrgent:NO
|
||||||
|
withProcessing:NO];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Because this could happen quite a bit after the inital set of files was
|
||||||
|
// captured, some could be completed (deleted). So, just double-check to make sure
|
||||||
|
// the file still exists.
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
for (NSString *path in self.preparedReportPaths) {
|
||||||
|
if (![[self.fileManager underlyingFileManager] fileExistsAtPath:path]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
[self.reportUploader uploadPackagedReportAtPath:path
|
||||||
|
dataCollectionToken:dataCollectionToken
|
||||||
|
asUrgent:NO];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)processExistingActiveReportPath:(NSString *)path
|
||||||
|
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
|
asUrgent:(BOOL)urgent {
|
||||||
|
FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
|
||||||
|
|
||||||
|
// TODO: hasAnyEvents should really be called on the background queue.
|
||||||
|
if (![report hasAnyEvents]) {
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
[self.fileManager removeItemAtPath:path];
|
||||||
|
}];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urgent && [dataCollectionToken isValid]) {
|
||||||
|
// We can proceed without the delegate.
|
||||||
|
[self.reportUploader prepareAndSubmitReport:report
|
||||||
|
dataCollectionToken:dataCollectionToken
|
||||||
|
asUrgent:urgent
|
||||||
|
withProcessing:YES];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
[self.reportUploader prepareAndSubmitReport:report
|
||||||
|
dataCollectionToken:dataCollectionToken
|
||||||
|
asUrgent:NO
|
||||||
|
withProcessing:YES];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)deleteUnsentReports {
|
||||||
|
NSArray<NSString *> *reportPaths = @[];
|
||||||
|
reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.existingUnemptyActiveReportPaths];
|
||||||
|
reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.processingReportPaths];
|
||||||
|
reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.preparedReportPaths];
|
||||||
|
|
||||||
|
[self.operationQueue addOperationWithBlock:^{
|
||||||
|
for (NSString *path in reportPaths) {
|
||||||
|
[self.fileManager removeItemAtPath:path];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
84
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h
generated
Normal file
84
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h
generated
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class FIRCLSFileManager;
|
||||||
|
@class FIRInstallations;
|
||||||
|
@class FIRCLSDataCollectionArbiter;
|
||||||
|
@class FIRCLSApplicationIdentifierModel;
|
||||||
|
@class FIRCLSInstallIdentifierModel;
|
||||||
|
@class FIRCLSExecutionIdentifierModel;
|
||||||
|
@class FIRCLSSettings;
|
||||||
|
@class FIRCLSLaunchMarkerModel;
|
||||||
|
@class GDTCORTransport;
|
||||||
|
@protocol FIRAnalyticsInterop;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manager Data's purpose is to simplify the adding and removing of
|
||||||
|
* dependencies from each of the Manager classes so that it's easier
|
||||||
|
* to inject mock classes during testing. A lot of the Manager classes
|
||||||
|
* share these dependencies, but don't use all of them.
|
||||||
|
*
|
||||||
|
* If you plan on adding interdependencies between Managers, do not add a pointer
|
||||||
|
* to the dependency here. Instead add them as a new value to the constructor of
|
||||||
|
* the Manager, and construct them in FIRCrashlytics. This data structure should
|
||||||
|
* be for Models and other SDKs / Interops Crashlytics depends on.
|
||||||
|
*/
|
||||||
|
@interface FIRCLSManagerData : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
|
||||||
|
googleTransport:(GDTCORTransport *)googleTransport
|
||||||
|
installations:(FIRInstallations *)installations
|
||||||
|
analytics:(nullable id<FIRAnalyticsInterop>)analytics
|
||||||
|
fileManager:(FIRCLSFileManager *)fileManager
|
||||||
|
dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter
|
||||||
|
settings:(FIRCLSSettings *)settings NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) NSString *googleAppID;
|
||||||
|
|
||||||
|
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
||||||
|
|
||||||
|
@property(nonatomic, strong) FIRInstallations *installations;
|
||||||
|
|
||||||
|
@property(nonatomic, strong) id<FIRAnalyticsInterop> analytics;
|
||||||
|
|
||||||
|
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
|
||||||
|
|
||||||
|
@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter;
|
||||||
|
|
||||||
|
// Uniquely identifies a build / binary of the app
|
||||||
|
@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel;
|
||||||
|
|
||||||
|
// Uniquely identifies an install of the app
|
||||||
|
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
|
||||||
|
|
||||||
|
// Uniquely identifies a run of the app
|
||||||
|
@property(nonatomic, strong) FIRCLSExecutionIdentifierModel *executionIDModel;
|
||||||
|
|
||||||
|
// Settings fetched from the server
|
||||||
|
@property(nonatomic, strong) FIRCLSSettings *settings;
|
||||||
|
|
||||||
|
// These queues function together as a single startup queue
|
||||||
|
@property(nonatomic, strong) NSOperationQueue *operationQueue;
|
||||||
|
@property(nonatomic, strong) dispatch_queue_t dispatchQueue;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
59
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.m
generated
Normal file
59
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.m
generated
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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 "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
|
||||||
|
|
||||||
|
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h"
|
||||||
|
|
||||||
|
@implementation FIRCLSManagerData
|
||||||
|
|
||||||
|
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
|
||||||
|
googleTransport:(GDTCORTransport *)googleTransport
|
||||||
|
installations:(FIRInstallations *)installations
|
||||||
|
analytics:(nullable id<FIRAnalyticsInterop>)analytics
|
||||||
|
fileManager:(FIRCLSFileManager *)fileManager
|
||||||
|
dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter
|
||||||
|
settings:(FIRCLSSettings *)settings {
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_googleAppID = googleAppID;
|
||||||
|
_googleTransport = googleTransport;
|
||||||
|
_installations = installations;
|
||||||
|
_analytics = analytics;
|
||||||
|
_fileManager = fileManager;
|
||||||
|
_dataArbiter = dataArbiter;
|
||||||
|
_settings = settings;
|
||||||
|
|
||||||
|
_appIDModel = [[FIRCLSApplicationIdentifierModel alloc] init];
|
||||||
|
_installIDModel = [[FIRCLSInstallIdentifierModel alloc] initWithInstallations:installations];
|
||||||
|
_executionIDModel = [[FIRCLSExecutionIdentifierModel alloc] init];
|
||||||
|
|
||||||
|
NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID();
|
||||||
|
_operationQueue = [NSOperationQueue new];
|
||||||
|
[_operationQueue setMaxConcurrentOperationCount:1];
|
||||||
|
[_operationQueue setName:[sdkBundleID stringByAppendingString:@".work-queue"]];
|
||||||
|
|
||||||
|
_dispatchQueue = dispatch_queue_create("com.google.firebase.crashlytics.startup", 0);
|
||||||
|
_operationQueue.underlyingQueue = _dispatchQueue;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -1,61 +0,0 @@
|
||||||
// Copyright 2019 Google
|
|
||||||
//
|
|
||||||
// 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>
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, FIRCLSNetworkClientErrorType) {
|
|
||||||
FIRCLSNetworkClientErrorTypeUnknown = -1,
|
|
||||||
FIRCLSNetworkClientErrorTypeFileUnreadable = -2
|
|
||||||
};
|
|
||||||
|
|
||||||
extern NSString *const FIRCLSNetworkClientErrorDomain;
|
|
||||||
|
|
||||||
@protocol FIRCLSNetworkClientDelegate;
|
|
||||||
@class FIRCLSDataCollectionToken;
|
|
||||||
@class FIRCLSFileManager;
|
|
||||||
|
|
||||||
@interface FIRCLSNetworkClient : NSObject
|
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
|
||||||
- (instancetype)initWithQueue:(NSOperationQueue *)queue
|
|
||||||
fileManager:(FIRCLSFileManager *)fileManager
|
|
||||||
delegate:(id<FIRCLSNetworkClientDelegate>)delegate;
|
|
||||||
|
|
||||||
@property(nonatomic, weak) id<FIRCLSNetworkClientDelegate> delegate;
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) NSOperationQueue *operationQueue;
|
|
||||||
@property(nonatomic, readonly) BOOL supportsBackgroundRequests;
|
|
||||||
|
|
||||||
- (void)startUploadRequest:(NSURLRequest *)request
|
|
||||||
filePath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
|
||||||
immediately:(BOOL)immediate;
|
|
||||||
|
|
||||||
- (void)attemptToReconnectBackgroundSessionWithCompletionBlock:(void (^)(void))completionBlock;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@class FIRCLSNetworkClient;
|
|
||||||
|
|
||||||
@protocol FIRCLSNetworkClientDelegate <NSObject>
|
|
||||||
@required
|
|
||||||
- (BOOL)networkClientCanUseBackgroundSessions:(FIRCLSNetworkClient *)client;
|
|
||||||
|
|
||||||
@optional
|
|
||||||
- (void)networkClient:(FIRCLSNetworkClient *)client
|
|
||||||
didFinishUploadWithPath:(NSString *)path
|
|
||||||
error:(NSError *)error;
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,366 +0,0 @@
|
||||||
// Copyright 2019 Google
|
|
||||||
//
|
|
||||||
// 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 "FIRCLSNetworkClient.h"
|
|
||||||
|
|
||||||
#import "FIRCLSApplication.h"
|
|
||||||
#import "FIRCLSByteUtility.h"
|
|
||||||
#import "FIRCLSDataCollectionToken.h"
|
|
||||||
#import "FIRCLSDefines.h"
|
|
||||||
#import "FIRCLSFileManager.h"
|
|
||||||
#import "FIRCLSNetworkResponseHandler.h"
|
|
||||||
#import "FIRCLSURLSession.h"
|
|
||||||
#import "FIRCLSURLSessionConfiguration.h"
|
|
||||||
|
|
||||||
#import "FIRCLSUtility.h"
|
|
||||||
|
|
||||||
NSString *const FIRCLSNetworkClientErrorDomain = @"FIRCLSNetworkError";
|
|
||||||
|
|
||||||
NSString *const FIRCLSNetworkClientBackgroundIdentifierSuffix = @".crash.background-session";
|
|
||||||
|
|
||||||
@interface FIRCLSNetworkClient () <NSURLSessionDelegate> {
|
|
||||||
NSURLSession *_session;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property(nonatomic, strong) void (^backgroundCompletionHandler)(void);
|
|
||||||
@property(nonatomic, strong, readonly) NSURLSession *session;
|
|
||||||
@property(nonatomic, assign) BOOL canUseBackgroundSession;
|
|
||||||
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation FIRCLSNetworkClient
|
|
||||||
|
|
||||||
- (instancetype)initWithQueue:(NSOperationQueue *)queue
|
|
||||||
fileManager:(FIRCLSFileManager *)fileManager
|
|
||||||
delegate:(id<FIRCLSNetworkClientDelegate>)delegate {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
_operationQueue = queue;
|
|
||||||
_delegate = delegate;
|
|
||||||
_fileManager = fileManager;
|
|
||||||
|
|
||||||
self.canUseBackgroundSession = [_delegate networkClientCanUseBackgroundSessions:self];
|
|
||||||
|
|
||||||
if (!self.supportsBackgroundRequests) {
|
|
||||||
FIRCLSDeveloperLog(
|
|
||||||
"Crashlytics:Crash:Client",
|
|
||||||
@"Background session uploading not supported, asynchronous uploading will be used");
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Background Support
|
|
||||||
- (NSURLSession *)session {
|
|
||||||
// Creating a NSURLSession takes some time. Doing it lazily saves us time in the normal case.
|
|
||||||
if (_session) {
|
|
||||||
return _session;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSURLSessionConfiguration *config = nil;
|
|
||||||
|
|
||||||
Class urlSessionClass;
|
|
||||||
Class urlSessionConfigurationClass;
|
|
||||||
#if FIRCLSURLSESSION_REQUIRED
|
|
||||||
urlSessionClass = [FIRCLSURLSession class];
|
|
||||||
urlSessionConfigurationClass = [FIRCLSURLSessionConfiguration class];
|
|
||||||
#else
|
|
||||||
urlSessionClass = [NSURLSession class];
|
|
||||||
urlSessionConfigurationClass = [NSURLSessionConfiguration class];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (self.supportsBackgroundRequests) {
|
|
||||||
NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID();
|
|
||||||
NSString *backgroundConfigName =
|
|
||||||
[sdkBundleID stringByAppendingString:FIRCLSNetworkClientBackgroundIdentifierSuffix];
|
|
||||||
|
|
||||||
config = [urlSessionConfigurationClass backgroundSessionConfiguration:backgroundConfigName];
|
|
||||||
#if TARGET_OS_IPHONE
|
|
||||||
[config setSessionSendsLaunchEvents:NO];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config) {
|
|
||||||
// take this code path if we don't support background requests OR if we failed to create a
|
|
||||||
// background configuration
|
|
||||||
config = [urlSessionConfigurationClass defaultSessionConfiguration];
|
|
||||||
}
|
|
||||||
|
|
||||||
_session = [urlSessionClass sessionWithConfiguration:config
|
|
||||||
delegate:self
|
|
||||||
delegateQueue:self.operationQueue];
|
|
||||||
|
|
||||||
if (!_session || !config) {
|
|
||||||
FIRCLSErrorLog(@"Failed to initialize");
|
|
||||||
}
|
|
||||||
|
|
||||||
return _session;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FIRCLSURLSESSION_REQUIRED
|
|
||||||
- (BOOL)NSURLSessionAvailable {
|
|
||||||
if ([[FIRCLSURLSession class] respondsToSelector:@selector(NSURLSessionShouldBeUsed)]) {
|
|
||||||
return [FIRCLSURLSession NSURLSessionShouldBeUsed];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NSClassFromString(@"NSURLSession") != nil;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- (BOOL)supportsBackgroundRequests {
|
|
||||||
return !FIRCLSApplicationIsExtension()
|
|
||||||
#if FIRCLSURLSESSION_REQUIRED
|
|
||||||
&& [self NSURLSessionAvailable]
|
|
||||||
#endif
|
|
||||||
&& self.canUseBackgroundSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)attemptToReconnectBackgroundSessionWithCompletionBlock:(void (^)(void))completionBlock {
|
|
||||||
if (!self.supportsBackgroundRequests) {
|
|
||||||
if (completionBlock) {
|
|
||||||
completionBlock();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the absolute minimum necessary. Perhaps we can do better?
|
|
||||||
if (completionBlock) {
|
|
||||||
[[NSOperationQueue mainQueue] addOperationWithBlock:completionBlock];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - API
|
|
||||||
- (void)startUploadRequest:(NSURLRequest *)request
|
|
||||||
filePath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
|
||||||
immediately:(BOOL)immediate {
|
|
||||||
if (![dataCollectionToken isValid]) {
|
|
||||||
FIRCLSErrorLog(@"An upload was requested with an invalid data collection token.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (immediate) {
|
|
||||||
[self startImmediateUploadRequest:request filePath:path];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *description = [self relativeTaskPathForAbsolutePath:path];
|
|
||||||
[self checkForExistingTaskMatchingDescription:description
|
|
||||||
completionBlock:^(BOOL found) {
|
|
||||||
if (found) {
|
|
||||||
FIRCLSDeveloperLog(
|
|
||||||
"Crashlytics:Crash:Client",
|
|
||||||
@"A task currently exists for this upload, skipping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self startNewUploadRequest:request filePath:path];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Support API
|
|
||||||
- (void)startImmediateUploadRequest:(NSURLRequest *)request filePath:(NSString *)path {
|
|
||||||
// check the ivar directly, to avoid going back to the delegate
|
|
||||||
if (self.supportsBackgroundRequests) {
|
|
||||||
// this can be done here, because the request will be started synchronously.
|
|
||||||
[self startNewUploadRequest:request filePath:path];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![[NSFileManager defaultManager] isReadableFileAtPath:path]) {
|
|
||||||
FIRCLSSDKLog("Error: file unreadable\n");
|
|
||||||
// Following the same logic as below, do not try to inform the delegate
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
|
||||||
|
|
||||||
[mutableRequest setHTTPBodyStream:[NSInputStream inputStreamWithFileAtPath:path]];
|
|
||||||
|
|
||||||
NSURLResponse *requestResponse = nil;
|
|
||||||
|
|
||||||
[[NSURLSession sharedSession]
|
|
||||||
dataTaskWithRequest:mutableRequest
|
|
||||||
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response,
|
|
||||||
NSError *_Nullable error) {
|
|
||||||
[FIRCLSNetworkResponseHandler
|
|
||||||
clientResponseType:requestResponse
|
|
||||||
handler:^(FIRCLSNetworkClientResponseType type, NSInteger statusCode) {
|
|
||||||
if (type != FIRCLSNetworkClientResponseSuccess) {
|
|
||||||
// don't even inform the delegate of a failure here, because we don't
|
|
||||||
// want any action to be taken synchronously
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[self delegate] networkClient:self
|
|
||||||
didFinishUploadWithPath:path
|
|
||||||
error:error];
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)startNewUploadRequest:(NSURLRequest *)request filePath:(NSString *)path {
|
|
||||||
if (![[NSFileManager defaultManager] isReadableFileAtPath:path]) {
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
[self
|
|
||||||
handleTaskDescription:path
|
|
||||||
completedWithError:[NSError errorWithDomain:FIRCLSNetworkClientErrorDomain
|
|
||||||
code:FIRCLSNetworkClientErrorTypeFileUnreadable
|
|
||||||
userInfo:@{@"path" : path}]];
|
|
||||||
}];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSURLSessionUploadTask *task = [self.session uploadTaskWithRequest:request
|
|
||||||
fromFile:[NSURL fileURLWithPath:path]];
|
|
||||||
|
|
||||||
// set the description, so we can determine what file was successfully uploaded later on
|
|
||||||
[task setTaskDescription:[self relativeTaskPathForAbsolutePath:path]];
|
|
||||||
|
|
||||||
[task resume];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)rootPath {
|
|
||||||
return self.fileManager.rootPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)absolutePathForRelativeTaskPath:(NSString *)path {
|
|
||||||
return [self.rootPath stringByAppendingPathComponent:path];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)relativeTaskPathForAbsolutePath:(NSString *)path {
|
|
||||||
// make sure this has a tailing slash, so the path looks relative
|
|
||||||
NSString *root = [self.rootPath stringByAppendingString:@"/"];
|
|
||||||
|
|
||||||
if (![path hasPrefix:root]) {
|
|
||||||
FIRCLSSDKLog("Error: path '%s' is not at the root '%s'", [path UTF8String], [root UTF8String]);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [path stringByReplacingOccurrencesOfString:root withString:@""];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Task Management
|
|
||||||
- (BOOL)taskArray:(NSArray *)array hasTaskMatchingDescription:(NSString *)description {
|
|
||||||
NSUInteger idx = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger arrayIdx, BOOL *stop) {
|
|
||||||
return [[obj taskDescription] isEqualToString:description];
|
|
||||||
}];
|
|
||||||
|
|
||||||
return idx != NSNotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)checkSession:(NSURLSession *)session
|
|
||||||
forTasksMatchingDescription:(NSString *)description
|
|
||||||
completionBlock:(void (^)(BOOL found))block {
|
|
||||||
if (!session) {
|
|
||||||
block(NO);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks,
|
|
||||||
NSArray *downloadTasks) {
|
|
||||||
if ([self taskArray:uploadTasks hasTaskMatchingDescription:description]) {
|
|
||||||
block(YES);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([self taskArray:dataTasks hasTaskMatchingDescription:description]) {
|
|
||||||
block(YES);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([self taskArray:downloadTasks hasTaskMatchingDescription:description]) {
|
|
||||||
block(YES);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
block(NO);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)checkForExistingTaskMatchingDescription:(NSString *)description
|
|
||||||
completionBlock:(void (^)(BOOL found))block {
|
|
||||||
// Do not instantiate the normal session, because if it doesn't exist yet, it cannot possibly have
|
|
||||||
// existing tasks
|
|
||||||
[_operationQueue addOperationWithBlock:^{
|
|
||||||
[self checkSession:self.session
|
|
||||||
forTasksMatchingDescription:description
|
|
||||||
completionBlock:^(BOOL found) {
|
|
||||||
block(found);
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Result Handling
|
|
||||||
// This method is duplicated from FIRCLSFABNetworkClient. Sharing it is a little weird - I didn't
|
|
||||||
// feel like it fit into FIRCLSNetworkResponseHandler.
|
|
||||||
- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response block:(void (^)(void))block {
|
|
||||||
NSTimeInterval delay = [FIRCLSNetworkResponseHandler retryValueForResponse:response];
|
|
||||||
|
|
||||||
// FIRCLSDeveloperLog("Network", @"Restarting request after %f", delay);
|
|
||||||
|
|
||||||
FIRCLSAddOperationAfter(delay, _operationQueue, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)restartTask:(NSURLSessionTask *)task {
|
|
||||||
NSURLRequest *request = [task originalRequest];
|
|
||||||
|
|
||||||
[self runAfterRetryValueFromResponse:[task response]
|
|
||||||
block:^{
|
|
||||||
NSString *path = [self
|
|
||||||
absolutePathForRelativeTaskPath:[task taskDescription]];
|
|
||||||
|
|
||||||
[self startNewUploadRequest:request filePath:path];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handleTask:(NSURLSessionTask *)task completedWithError:(NSError *)error {
|
|
||||||
[self handleTaskDescription:[task taskDescription] completedWithError:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handleTaskDescription:(NSString *)taskDescription completedWithError:(NSError *)error {
|
|
||||||
NSString *path = [self absolutePathForRelativeTaskPath:taskDescription];
|
|
||||||
|
|
||||||
[[self delegate] networkClient:self didFinishUploadWithPath:path error:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSURLSessionDelegate
|
|
||||||
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Client", @"session became invalid: %@", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Careful! Not implementing this method appears to cause a crash when using a background task
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
|
||||||
task:(NSURLSessionTask *)task
|
|
||||||
didCompleteWithError:(NSError *)error {
|
|
||||||
[FIRCLSNetworkResponseHandler handleCompletedResponse:task.response
|
|
||||||
forOriginalRequest:task.originalRequest
|
|
||||||
error:error
|
|
||||||
block:^(BOOL restart, NSError *taskError) {
|
|
||||||
if (restart) {
|
|
||||||
[self restartTask:task];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self handleTask:task
|
|
||||||
completedWithError:taskError];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2019 Google
|
// Copyright 2021 Google LLC
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -12,16 +12,16 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FIRCLSURLSessionAvailability.h"
|
|
||||||
|
|
||||||
#if FIRCLSURLSESSION_REQUIRED
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
@interface FIRCLSURLSession (PrivateMethods)
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
- (void)runOnDelegateQueue:(void (^)(void))block;
|
@interface FIRCLSNotificationManager : NSObject
|
||||||
|
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
- (void)registerNotificationListener;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
NS_ASSUME_NONNULL_END
|
110
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.m
generated
Normal file
110
ios/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.m
generated
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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 "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h"
|
||||||
|
|
||||||
|
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#else
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@implementation FIRCLSNotificationManager
|
||||||
|
|
||||||
|
- (void)registerNotificationListener {
|
||||||
|
[self captureInitialNotificationStates];
|
||||||
|
|
||||||
|
#if TARGET_OS_IOS
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(willBecomeActive:)
|
||||||
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(didBecomeInactive:)
|
||||||
|
name:UIApplicationDidEnterBackgroundNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(didChangeOrientation:)
|
||||||
|
name:UIDeviceOrientationDidChangeNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserver:self
|
||||||
|
selector:@selector(didChangeUIOrientation:)
|
||||||
|
name:UIApplicationDidChangeStatusBarOrientationNotification
|
||||||
|
object:nil];
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
#elif CLS_TARGET_OS_OSX
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(willBecomeActive:)
|
||||||
|
name:@"NSApplicationWillBecomeActiveNotification"
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(didBecomeInactive:)
|
||||||
|
name:@"NSApplicationDidResignActiveNotification"
|
||||||
|
object:nil];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)captureInitialNotificationStates {
|
||||||
|
#if TARGET_OS_IOS
|
||||||
|
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
|
||||||
|
UIInterfaceOrientation statusBarOrientation =
|
||||||
|
[FIRCLSApplicationSharedInstance() statusBarOrientation];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// It's nice to do this async, so we don't hold up the main thread while doing three
|
||||||
|
// consecutive IOs here.
|
||||||
|
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
||||||
|
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSInBackgroundKey, @"0");
|
||||||
|
#if TARGET_OS_IOS
|
||||||
|
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSDeviceOrientationKey,
|
||||||
|
[@(orientation) description]);
|
||||||
|
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSUIOrientationKey,
|
||||||
|
[@(statusBarOrientation) description]);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)willBecomeActive:(NSNotification *)notification {
|
||||||
|
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didBecomeInactive:(NSNotification *)notification {
|
||||||
|
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TARGET_OS_IOS
|
||||||
|
- (void)didChangeOrientation:(NSNotification *)notification {
|
||||||
|
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
|
||||||
|
|
||||||
|
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDeviceOrientationKey, @(orientation));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didChangeUIOrientation:(NSNotification *)notification {
|
||||||
|
UIInterfaceOrientation statusBarOrientation =
|
||||||
|
[FIRCLSApplicationSharedInstance() statusBarOrientation];
|
||||||
|
|
||||||
|
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSUIOrientationKey, @(statusBarOrientation));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@end
|
|
@ -14,38 +14,29 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#include "FIRCLSApplicationIdentifierModel.h"
|
#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h"
|
||||||
#include "FIRCLSProfiling.h"
|
|
||||||
#include "FIRCrashlytics.h"
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSProfiling.h"
|
||||||
|
|
||||||
@class FBLPromise<T>;
|
@class FBLPromise<T>;
|
||||||
|
@class FIRCLSExistingReportManager;
|
||||||
|
@class FIRCLSAnalyticsManager;
|
||||||
|
@class FIRCLSManagerData;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@class FIRCLSDataCollectionArbiter;
|
|
||||||
@class FIRCLSFileManager;
|
|
||||||
@class FIRCLSInternalReport;
|
|
||||||
@class FIRCLSSettings;
|
|
||||||
@class GDTCORTransport;
|
|
||||||
@class FIRInstallations;
|
|
||||||
@protocol FIRAnalyticsInterop;
|
|
||||||
|
|
||||||
@interface FIRCLSReportManager : NSObject
|
@interface FIRCLSReportManager : NSObject
|
||||||
|
|
||||||
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager
|
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
|
||||||
installations:(FIRInstallations *)installations
|
existingReportManager:(FIRCLSExistingReportManager *)existingReportManager
|
||||||
analytics:(nullable id<FIRAnalyticsInterop>)analytics
|
analyticsManager:(FIRCLSAnalyticsManager *)analyticsManager
|
||||||
googleAppID:(NSString *)googleAppID
|
NS_DESIGNATED_INITIALIZER;
|
||||||
dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter
|
|
||||||
googleTransport:(GDTCORTransport *)googleTransport
|
|
||||||
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel
|
|
||||||
settings:(FIRCLSSettings *)settings NS_DESIGNATED_INITIALIZER;
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
- (FBLPromise<NSNumber *> *)startWithProfilingMark:(FIRCLSProfileMark)mark;
|
- (FBLPromise<NSNumber *> *)startWithProfilingMark:(FIRCLSProfileMark)mark;
|
||||||
|
|
||||||
- (FBLPromise<NSNumber *> *)checkForUnsentReports;
|
- (FBLPromise<FIRCrashlyticsReport *> *)checkForUnsentReports;
|
||||||
- (FBLPromise *)sendUnsentReports;
|
- (FBLPromise *)sendUnsentReports;
|
||||||
- (FBLPromise *)deleteUnsentReports;
|
- (FBLPromise *)deleteUnsentReports;
|
||||||
|
|
||||||
|
|
|
@ -38,37 +38,34 @@
|
||||||
#import "FBLPromises.h"
|
#import "FBLPromises.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#import "FIRCLSApplication.h"
|
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
#import "FIRCLSDataCollectionArbiter.h"
|
#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||||
#import "FIRCLSDataCollectionToken.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
|
||||||
#import "FIRCLSDefines.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h"
|
||||||
#import "FIRCLSFeatures.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
|
||||||
#import "FIRCLSFileManager.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h"
|
||||||
#import "FIRCLSInternalReport.h"
|
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
|
||||||
#import "FIRCLSLogger.h"
|
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||||
#import "FIRCLSNetworkClient.h"
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||||
#import "FIRCLSPackageReportOperation.h"
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||||
#import "FIRCLSProcessReportOperation.h"
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
|
||||||
#import "FIRCLSReportUploader.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||||
#import "FIRCLSSettings.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||||
#import "FIRCLSSymbolResolver.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h"
|
||||||
#import "FIRCLSUserLogging.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h"
|
||||||
|
|
||||||
#include "FIRCLSGlobals.h"
|
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
#import "FIRCLSConstants.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h"
|
||||||
#import "FIRCLSExecutionIdentifierModel.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||||
#import "FIRCLSInstallIdentifierModel.h"
|
#import "Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h"
|
||||||
#import "FIRCLSSettingsOnboardingManager.h"
|
#import "Crashlytics/Shared/FIRCLSConstants.h"
|
||||||
|
|
||||||
#import "FIRCLSReportManager_Private.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h"
|
||||||
|
|
||||||
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
|
||||||
#import "Interop/Analytics/Public/FIRAnalyticsInteropListener.h"
|
|
||||||
|
|
||||||
#include "FIRAEvent+Internal.h"
|
|
||||||
#include "FIRCLSFCRAnalytics.h"
|
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
@ -76,29 +73,6 @@
|
||||||
#import <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static NSTimeInterval const CLSReportRetryInterval = 10 * 60;
|
|
||||||
|
|
||||||
static NSString *FIRCLSFirebaseAnalyticsEventLogFormat = @"$A$:%@";
|
|
||||||
|
|
||||||
@interface FIRCLSAnalyticsInteropListener : NSObject <FIRAnalyticsInteropListener> {
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation FIRCLSAnalyticsInteropListener
|
|
||||||
|
|
||||||
- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters {
|
|
||||||
NSDictionary *event = @{
|
|
||||||
@"name" : name,
|
|
||||||
@"parameters" : parameters,
|
|
||||||
};
|
|
||||||
NSString *json = FIRCLSFIRAEventDictionaryToJSON(event);
|
|
||||||
if (json != nil) {
|
|
||||||
FIRCLSLog(FIRCLSFirebaseAnalyticsEventLogFormat, json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A FIRReportAction is used to indicate how to handle unsent reports.
|
* A FIRReportAction is used to indicate how to handle unsent reports.
|
||||||
*/
|
*/
|
||||||
|
@ -119,24 +93,15 @@ typedef NSNumber FIRCLSWrappedReportAction;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
@interface FIRCLSReportManager () {
|
||||||
* This is a helper to make code using NSNumber for bools more readable.
|
|
||||||
*/
|
|
||||||
typedef NSNumber FIRCLSWrappedBool;
|
|
||||||
|
|
||||||
@interface FIRCLSReportManager () <FIRCLSNetworkClientDelegate,
|
|
||||||
FIRCLSReportUploaderDelegate,
|
|
||||||
FIRCLSReportUploaderDataSource> {
|
|
||||||
FIRCLSFileManager *_fileManager;
|
FIRCLSFileManager *_fileManager;
|
||||||
FIRCLSNetworkClient *_networkClient;
|
|
||||||
FIRCLSReportUploader *_uploader;
|
|
||||||
dispatch_queue_t _dispatchQueue;
|
dispatch_queue_t _dispatchQueue;
|
||||||
NSOperationQueue *_operationQueue;
|
NSOperationQueue *_operationQueue;
|
||||||
id<FIRAnalyticsInterop> _analytics;
|
id<FIRAnalyticsInterop> _analytics;
|
||||||
|
|
||||||
// A promise that will be resolved when unsent reports are found on the device, and
|
// A promise that will be resolved when unsent reports are found on the device, and
|
||||||
// processReports: can be called to decide how to deal with them.
|
// processReports: can be called to decide how to deal with them.
|
||||||
FBLPromise<FIRCLSWrappedBool *> *_unsentReportsAvailable;
|
FBLPromise<FIRCrashlyticsReport *> *_unsentReportsAvailable;
|
||||||
|
|
||||||
// A promise that will be resolved when the user has provided an action that they want to perform
|
// A promise that will be resolved when the user has provided an action that they want to perform
|
||||||
// for all the unsent reports.
|
// for all the unsent reports.
|
||||||
|
@ -156,63 +121,49 @@ typedef NSNumber FIRCLSWrappedBool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property(nonatomic, readonly) NSString *googleAppID;
|
@property(nonatomic, readonly) NSString *googleAppID;
|
||||||
|
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
||||||
|
|
||||||
@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter;
|
@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter;
|
||||||
|
@property(nonatomic, strong) FIRCLSSettings *settings;
|
||||||
|
@property(nonatomic, strong) FIRCLSLaunchMarkerModel *launchMarker;
|
||||||
|
|
||||||
// Uniquely identifies a build / binary of the app
|
|
||||||
@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel;
|
@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel;
|
||||||
|
|
||||||
// Uniquely identifies an install of the app
|
|
||||||
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
|
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
|
||||||
|
|
||||||
// Uniquely identifies a run of the app
|
|
||||||
@property(nonatomic, strong) FIRCLSExecutionIdentifierModel *executionIDModel;
|
@property(nonatomic, strong) FIRCLSExecutionIdentifierModel *executionIDModel;
|
||||||
|
|
||||||
// Settings fetched from the server
|
@property(nonatomic, strong) FIRCLSAnalyticsManager *analyticsManager;
|
||||||
@property(nonatomic, strong) FIRCLSSettings *settings;
|
@property(nonatomic, strong) FIRCLSExistingReportManager *existingReportManager;
|
||||||
|
|
||||||
// Runs the operations that fetch settings and call onboarding endpoints
|
// Internal Managers
|
||||||
@property(nonatomic, strong) FIRCLSSettingsOnboardingManager *settingsAndOnboardingManager;
|
@property(nonatomic, strong) FIRCLSSettingsManager *settingsManager;
|
||||||
|
@property(nonatomic, strong) FIRCLSNotificationManager *notificationManager;
|
||||||
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation FIRCLSReportManager
|
@implementation FIRCLSReportManager
|
||||||
|
|
||||||
// Used only for internal data collection E2E testing
|
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
|
||||||
static void (^reportSentCallback)(void);
|
existingReportManager:(FIRCLSExistingReportManager *)existingReportManager
|
||||||
|
analyticsManager:(FIRCLSAnalyticsManager *)analyticsManager {
|
||||||
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager
|
|
||||||
installations:(FIRInstallations *)installations
|
|
||||||
analytics:(id<FIRAnalyticsInterop>)analytics
|
|
||||||
googleAppID:(NSString *)googleAppID
|
|
||||||
dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter
|
|
||||||
googleTransport:(GDTCORTransport *)googleTransport
|
|
||||||
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel
|
|
||||||
settings:(FIRCLSSettings *)settings {
|
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fileManager = fileManager;
|
_fileManager = managerData.fileManager;
|
||||||
_analytics = analytics;
|
_analytics = managerData.analytics;
|
||||||
_googleAppID = [googleAppID copy];
|
_googleAppID = [managerData.googleAppID copy];
|
||||||
_dataArbiter = dataArbiter;
|
_dataArbiter = managerData.dataArbiter;
|
||||||
|
_googleTransport = managerData.googleTransport;
|
||||||
|
_operationQueue = managerData.operationQueue;
|
||||||
|
_dispatchQueue = managerData.dispatchQueue;
|
||||||
|
_appIDModel = managerData.appIDModel;
|
||||||
|
_installIDModel = managerData.installIDModel;
|
||||||
|
_settings = managerData.settings;
|
||||||
|
_executionIDModel = managerData.executionIDModel;
|
||||||
|
|
||||||
_googleTransport = googleTransport;
|
_existingReportManager = existingReportManager;
|
||||||
|
_analyticsManager = analyticsManager;
|
||||||
NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID();
|
|
||||||
|
|
||||||
_operationQueue = [NSOperationQueue new];
|
|
||||||
[_operationQueue setMaxConcurrentOperationCount:1];
|
|
||||||
[_operationQueue setName:[sdkBundleID stringByAppendingString:@".work-queue"]];
|
|
||||||
|
|
||||||
_dispatchQueue = dispatch_queue_create("com.google.firebase.crashlytics.startup", 0);
|
|
||||||
_operationQueue.underlyingQueue = _dispatchQueue;
|
|
||||||
|
|
||||||
_networkClient = [self clientWithOperationQueue:_operationQueue];
|
|
||||||
|
|
||||||
_unsentReportsAvailable = [FBLPromise pendingPromise];
|
_unsentReportsAvailable = [FBLPromise pendingPromise];
|
||||||
_reportActionProvided = [FBLPromise pendingPromise];
|
_reportActionProvided = [FBLPromise pendingPromise];
|
||||||
|
@ -220,42 +171,19 @@ static void (^reportSentCallback)(void);
|
||||||
|
|
||||||
_checkForUnsentReportsCalled = NO;
|
_checkForUnsentReportsCalled = NO;
|
||||||
|
|
||||||
_installIDModel = [[FIRCLSInstallIdentifierModel alloc] initWithInstallations:installations];
|
_settingsManager = [[FIRCLSSettingsManager alloc] initWithAppIDModel:self.appIDModel
|
||||||
_executionIDModel = [[FIRCLSExecutionIdentifierModel alloc] init];
|
installIDModel:self.installIDModel
|
||||||
|
settings:self.settings
|
||||||
|
fileManager:self.fileManager
|
||||||
|
googleAppID:self.googleAppID];
|
||||||
|
|
||||||
_settings = settings;
|
_notificationManager = [[FIRCLSNotificationManager alloc] init];
|
||||||
_appIDModel = appIDModel;
|
|
||||||
|
|
||||||
_settingsAndOnboardingManager =
|
_launchMarker = [[FIRCLSLaunchMarkerModel alloc] initWithFileManager:_fileManager];
|
||||||
[[FIRCLSSettingsOnboardingManager alloc] initWithAppIDModel:appIDModel
|
|
||||||
installIDModel:self.installIDModel
|
|
||||||
settings:self.settings
|
|
||||||
fileManager:self.fileManager
|
|
||||||
googleAppID:self.googleAppID];
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FIRCLSNetworkClient *)clientWithOperationQueue:(NSOperationQueue *)queue {
|
|
||||||
return [[FIRCLSNetworkClient alloc] initWithQueue:queue fileManager:_fileManager delegate:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of unsent reports on the device, including the ones passed in.
|
|
||||||
*/
|
|
||||||
- (int)unsentReportsCountWithPreexisting:(NSArray<NSString *> *)paths {
|
|
||||||
int count = [self countSubmittableAndDeleteUnsubmittableReportPaths:paths];
|
|
||||||
|
|
||||||
count += _fileManager.processingPathContents.count;
|
|
||||||
|
|
||||||
if (self.settings.shouldUseNewReportEndpoint) {
|
|
||||||
count += _fileManager.preparedPathContents.count;
|
|
||||||
} else {
|
|
||||||
count += _fileManager.legacyPreparedPathContents.count;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method returns a promise that is resolved with a wrapped FIRReportAction once the user has
|
// This method returns a promise that is resolved with a wrapped FIRReportAction once the user has
|
||||||
// indicated whether they want to upload currently cached reports.
|
// indicated whether they want to upload currently cached reports.
|
||||||
// This method should only be called when we have determined there is at least 1 unsent report.
|
// This method should only be called when we have determined there is at least 1 unsent report.
|
||||||
|
@ -264,8 +192,8 @@ static void (^reportSentCallback)(void);
|
||||||
// 2. The developer uses the processCrashReports API to indicate whether the report
|
// 2. The developer uses the processCrashReports API to indicate whether the report
|
||||||
// should be sent or deleted, at which point the promise will be resolved with the action.
|
// should be sent or deleted, at which point the promise will be resolved with the action.
|
||||||
- (FBLPromise<FIRCLSWrappedReportAction *> *)waitForReportAction {
|
- (FBLPromise<FIRCLSWrappedReportAction *> *)waitForReportAction {
|
||||||
FIRCLSDebugLog(@"[Crashlytics:Crash] Notifying that unsent reports are available.");
|
FIRCrashlyticsReport *unsentReport = self.existingReportManager.newestUnsentReport;
|
||||||
[_unsentReportsAvailable fulfill:@YES];
|
[_unsentReportsAvailable fulfill:unsentReport];
|
||||||
|
|
||||||
// If data collection gets enabled while we are waiting for an action, go ahead and send the
|
// If data collection gets enabled while we are waiting for an action, go ahead and send the
|
||||||
// reports, and any subsequent explicit response will be ignored.
|
// reports, and any subsequent explicit response will be ignored.
|
||||||
|
@ -275,16 +203,16 @@ static void (^reportSentCallback)(void);
|
||||||
return @(FIRCLSReportActionSend);
|
return @(FIRCLSReportActionSend);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
FIRCLSDebugLog(@"[Crashlytics:Crash] Waiting for send/deleteUnsentReports to be called.");
|
|
||||||
// Wait for either the processReports callback to be called, or data collection to be enabled.
|
// Wait for either the processReports callback to be called, or data collection to be enabled.
|
||||||
return [FBLPromise race:@[ collectionEnabled, _reportActionProvided ]];
|
return [FBLPromise race:@[ collectionEnabled, _reportActionProvided ]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FBLPromise<FIRCLSWrappedBool *> *)checkForUnsentReports {
|
- (FBLPromise<FIRCrashlyticsReport *> *)checkForUnsentReports {
|
||||||
bool expectedCalled = NO;
|
bool expectedCalled = NO;
|
||||||
if (!atomic_compare_exchange_strong(&_checkForUnsentReportsCalled, &expectedCalled, YES)) {
|
if (!atomic_compare_exchange_strong(&_checkForUnsentReportsCalled, &expectedCalled, YES)) {
|
||||||
FIRCLSErrorLog(@"checkForUnsentReports should only be called once per execution.");
|
FIRCLSErrorLog(@"Either checkForUnsentReports or checkAndUpdateUnsentReports should be called "
|
||||||
return [FBLPromise resolvedWith:@NO];
|
@"once per execution.");
|
||||||
|
return [FBLPromise resolvedWith:nil];
|
||||||
}
|
}
|
||||||
return _unsentReportsAvailable;
|
return _unsentReportsAvailable;
|
||||||
}
|
}
|
||||||
|
@ -306,6 +234,10 @@ static void (^reportSentCallback)(void);
|
||||||
NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
|
NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
|
||||||
[self.settings reloadFromCacheWithGoogleAppID:self.googleAppID currentTimestamp:currentTimestamp];
|
[self.settings reloadFromCacheWithGoogleAppID:self.googleAppID currentTimestamp:currentTimestamp];
|
||||||
|
|
||||||
|
// This needs to be called before the new report is created for
|
||||||
|
// this run of the app.
|
||||||
|
[self.existingReportManager collectExistingReports];
|
||||||
|
|
||||||
if (![self validateAppIdentifiers]) {
|
if (![self validateAppIdentifiers]) {
|
||||||
return [FBLPromise resolvedWith:@NO];
|
return [FBLPromise resolvedWith:@NO];
|
||||||
}
|
}
|
||||||
|
@ -314,26 +246,11 @@ static void (^reportSentCallback)(void);
|
||||||
FIRCLSDebugLog(@"Root: %@", [_fileManager rootPath]);
|
FIRCLSDebugLog(@"Root: %@", [_fileManager rootPath]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ([self.dataArbiter isLegacyDataCollectionKeyInPlist]) {
|
|
||||||
FIRCLSErrorLog(@"Found legacy data collection key in app's Info.plist: "
|
|
||||||
@"firebase_crashlytics_collection_enabled");
|
|
||||||
FIRCLSErrorLog(@"Please update your Info.plist to use the new data collection key: "
|
|
||||||
@"FirebaseCrashlyticsCollectionEnabled");
|
|
||||||
FIRCLSErrorLog(@"The legacy data collection Info.plist value could be overridden by "
|
|
||||||
@"calling: [Fabric with:...]");
|
|
||||||
FIRCLSErrorLog(@"The new value can be overridden by calling: [[FIRCrashlytics "
|
|
||||||
@"crashlytics] setCrashlyticsCollectionEnabled:<isEnabled>]");
|
|
||||||
|
|
||||||
return [FBLPromise resolvedWith:@NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![_fileManager createReportDirectories]) {
|
if (![_fileManager createReportDirectories]) {
|
||||||
return [FBLPromise resolvedWith:@NO];
|
return [FBLPromise resolvedWith:@NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab existing reports
|
BOOL launchFailure = [self.launchMarker checkForAndCreateLaunchMarker];
|
||||||
BOOL launchFailure = [self checkForAndCreateLaunchMarker];
|
|
||||||
NSArray *preexistingReportPaths = _fileManager.activePathContents;
|
|
||||||
|
|
||||||
FIRCLSInternalReport *report = [self setupCurrentReport:executionIdentifier];
|
FIRCLSInternalReport *report = [self setupCurrentReport:executionIdentifier];
|
||||||
if (!report) {
|
if (!report) {
|
||||||
|
@ -345,14 +262,6 @@ static void (^reportSentCallback)(void);
|
||||||
report = nil;
|
report = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regenerate the Install ID on a background thread if it needs to rotate because
|
|
||||||
// fetching the Firebase Install ID can be slow on some devices. This should happen after we
|
|
||||||
// create the session on disk so that we can update the Install ID in the written crash report
|
|
||||||
// metadata.
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
|
||||||
[self checkAndRotateInstallUUIDIfNeededWithReport:report];
|
|
||||||
});
|
|
||||||
|
|
||||||
FBLPromise<NSNumber *> *promise = [FBLPromise resolvedWith:@(report != nil)];
|
FBLPromise<NSNumber *> *promise = [FBLPromise resolvedWith:@(report != nil)];
|
||||||
|
|
||||||
if ([self.dataArbiter isCrashlyticsCollectionEnabled]) {
|
if ([self.dataArbiter isCrashlyticsCollectionEnabled]) {
|
||||||
|
@ -360,64 +269,43 @@ static void (^reportSentCallback)(void);
|
||||||
FIRCLSDebugLog(@"Unsent reports will be uploaded at startup");
|
FIRCLSDebugLog(@"Unsent reports will be uploaded at startup");
|
||||||
FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken];
|
FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken];
|
||||||
|
|
||||||
[self beginSettingsAndOnboardingWithToken:dataCollectionToken waitForSettingsRequest:NO];
|
[self beginSettingsWithToken:dataCollectionToken];
|
||||||
|
|
||||||
[self beginReportUploadsWithToken:dataCollectionToken
|
[self beginReportUploadsWithToken:dataCollectionToken blockingSend:launchFailure];
|
||||||
preexistingReportPaths:preexistingReportPaths
|
|
||||||
blockingSend:launchFailure
|
|
||||||
report:report];
|
|
||||||
|
|
||||||
// If data collection is enabled, the SDK will not notify the user
|
// If data collection is enabled, the SDK will not notify the user
|
||||||
// when unsent reports are available, or respect Send / DeleteUnsentReports
|
// when unsent reports are available, or respect Send / DeleteUnsentReports
|
||||||
[_unsentReportsAvailable fulfill:@NO];
|
[_unsentReportsAvailable fulfill:nil];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
FIRCLSDebugLog(@"Automatic data collection is disabled.");
|
FIRCLSDebugLog(@"Automatic data collection is disabled.");
|
||||||
|
FIRCLSDebugLog(@"[Crashlytics:Crash] %d unsent reports are available. Waiting for "
|
||||||
|
@"send/deleteUnsentReports to be called.",
|
||||||
|
self.existingReportManager.unsentReportsCount);
|
||||||
|
|
||||||
// TODO: This counting of the file system happens on the main thread. Now that some of the other
|
// Wait for an action to get sent, either from processReports: or automatic data collection.
|
||||||
// work below has been made async and moved to the dispatch queue, maybe we can move this code
|
promise = [[self waitForReportAction]
|
||||||
// to the dispatch queue as well.
|
onQueue:_dispatchQueue
|
||||||
int unsentReportsCount = [self unsentReportsCountWithPreexisting:preexistingReportPaths];
|
then:^id _Nullable(FIRCLSWrappedReportAction *_Nullable wrappedAction) {
|
||||||
if (unsentReportsCount > 0) {
|
// Process the actions for the reports on disk.
|
||||||
FIRCLSDebugLog(
|
FIRCLSReportAction action = [wrappedAction reportActionValue];
|
||||||
@"[Crashlytics:Crash] %d unsent reports are available. Checking for upload permission.",
|
if (action == FIRCLSReportActionSend) {
|
||||||
unsentReportsCount);
|
FIRCLSDebugLog(@"Sending unsent reports.");
|
||||||
// Wait for an action to get sent, either from processReports: or automatic data collection.
|
FIRCLSDataCollectionToken *dataCollectionToken =
|
||||||
promise = [[self waitForReportAction]
|
[FIRCLSDataCollectionToken validToken];
|
||||||
onQueue:_dispatchQueue
|
|
||||||
then:^id _Nullable(FIRCLSWrappedReportAction *_Nullable wrappedAction) {
|
|
||||||
// Process the actions for the reports on disk.
|
|
||||||
FIRCLSReportAction action = [wrappedAction reportActionValue];
|
|
||||||
if (action == FIRCLSReportActionSend) {
|
|
||||||
FIRCLSDebugLog(@"Sending unsent reports.");
|
|
||||||
FIRCLSDataCollectionToken *dataCollectionToken =
|
|
||||||
[FIRCLSDataCollectionToken validToken];
|
|
||||||
|
|
||||||
// For the new report endpoint, the orgID is not needed.
|
[self beginSettingsWithToken:dataCollectionToken];
|
||||||
// For the legacy report endpoint, wait on settings if orgID is not available.
|
|
||||||
BOOL waitForSetting =
|
|
||||||
!self.settings.shouldUseNewReportEndpoint && !self.settings.orgID;
|
|
||||||
|
|
||||||
[self beginSettingsAndOnboardingWithToken:dataCollectionToken
|
[self beginReportUploadsWithToken:dataCollectionToken blockingSend:NO];
|
||||||
waitForSettingsRequest:waitForSetting];
|
|
||||||
|
|
||||||
[self beginReportUploadsWithToken:dataCollectionToken
|
} else if (action == FIRCLSReportActionDelete) {
|
||||||
preexistingReportPaths:preexistingReportPaths
|
FIRCLSDebugLog(@"Deleting unsent reports.");
|
||||||
blockingSend:NO
|
[self.existingReportManager deleteUnsentReports];
|
||||||
report:report];
|
} else {
|
||||||
|
FIRCLSErrorLog(@"Unknown report action: %d", action);
|
||||||
} else if (action == FIRCLSReportActionDelete) {
|
}
|
||||||
FIRCLSDebugLog(@"Deleting unsent reports.");
|
return @(report != nil);
|
||||||
[self deleteUnsentReportsWithPreexisting:preexistingReportPaths];
|
}];
|
||||||
} else {
|
|
||||||
FIRCLSErrorLog(@"Unknown report action: %d", action);
|
|
||||||
}
|
|
||||||
return @(report != nil);
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
FIRCLSDebugLog(@"[Crashlytics:Crash] There are no unsent reports.");
|
|
||||||
[_unsentReportsAvailable fulfill:@NO];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report != nil) {
|
if (report != nil) {
|
||||||
|
@ -435,52 +323,42 @@ static void (^reportSentCallback)(void);
|
||||||
NSOperationQueue *__weak queue = _operationQueue;
|
NSOperationQueue *__weak queue = _operationQueue;
|
||||||
FBLPromise *__weak unsentReportsHandled = _unsentReportsHandled;
|
FBLPromise *__weak unsentReportsHandled = _unsentReportsHandled;
|
||||||
promise = [promise then:^id _Nullable(NSNumber *_Nullable value) {
|
promise = [promise then:^id _Nullable(NSNumber *_Nullable value) {
|
||||||
[queue waitUntilAllOperationsAreFinished];
|
FBLPromise *allOpsFinished = [FBLPromise pendingPromise];
|
||||||
// Signal that to callers of processReports that everything is finished.
|
[queue addOperationWithBlock:^{
|
||||||
[unsentReportsHandled fulfill:nil];
|
[allOpsFinished fulfill:nil];
|
||||||
return value;
|
}];
|
||||||
|
|
||||||
|
return [allOpsFinished onQueue:dispatch_get_main_queue()
|
||||||
|
then:^id _Nullable(id _Nullable allOpsFinishedValue) {
|
||||||
|
// Signal that to callers of processReports that everything is
|
||||||
|
// finished.
|
||||||
|
[unsentReportsHandled fulfill:nil];
|
||||||
|
return value;
|
||||||
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)checkAndRotateInstallUUIDIfNeededWithReport:(FIRCLSInternalReport *)report {
|
- (void)beginSettingsWithToken:(FIRCLSDataCollectionToken *)token {
|
||||||
[self.installIDModel regenerateInstallIDIfNeededWithBlock:^(BOOL didRotate) {
|
|
||||||
if (!didRotate) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FIRCLSContextUpdateMetadata(report, self.settings, self.installIDModel, self->_fileManager);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)beginSettingsAndOnboardingWithToken:(FIRCLSDataCollectionToken *)token
|
|
||||||
waitForSettingsRequest:(BOOL)waitForSettings {
|
|
||||||
if (self.settings.isCacheExpired) {
|
if (self.settings.isCacheExpired) {
|
||||||
// This method can be called more than once if the user calls
|
// This method can be called more than once if the user calls
|
||||||
// SendUnsentReports again, so don't repeat the settings fetch
|
// SendUnsentReports again, so don't repeat the settings fetch
|
||||||
static dispatch_once_t settingsFetchOnceToken;
|
static dispatch_once_t settingsFetchOnceToken;
|
||||||
dispatch_once(&settingsFetchOnceToken, ^{
|
dispatch_once(&settingsFetchOnceToken, ^{
|
||||||
[self.settingsAndOnboardingManager beginSettingsAndOnboardingWithGoogleAppId:self.googleAppID
|
[self.settingsManager beginSettingsWithGoogleAppId:self.googleAppID token:token];
|
||||||
token:token
|
|
||||||
waitForCompletion:waitForSettings];
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)beginReportUploadsWithToken:(FIRCLSDataCollectionToken *)token
|
- (void)beginReportUploadsWithToken:(FIRCLSDataCollectionToken *)token
|
||||||
preexistingReportPaths:(NSArray *)preexistingReportPaths
|
blockingSend:(BOOL)blockingSend {
|
||||||
blockingSend:(BOOL)blockingSend
|
|
||||||
report:(FIRCLSInternalReport *)report {
|
|
||||||
if (self.settings.collectReportsEnabled) {
|
if (self.settings.collectReportsEnabled) {
|
||||||
[self processExistingReportPaths:preexistingReportPaths
|
[self.existingReportManager sendUnsentReportsWithToken:token asUrgent:blockingSend];
|
||||||
dataCollectionToken:token
|
|
||||||
asUrgent:blockingSend];
|
|
||||||
[self handleContentsInOtherReportingDirectoriesWithToken:token];
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
FIRCLSInfoLog(@"Collect crash reports is disabled");
|
FIRCLSInfoLog(@"Collect crash reports is disabled");
|
||||||
[self deleteUnsentReportsWithPreexisting:preexistingReportPaths];
|
[self.existingReportManager deleteUnsentReports];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,13 +368,13 @@ static void (^reportSentCallback)(void);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FIRCLSContextInitialize(report, self.settings, self.installIDModel, _fileManager)) {
|
if (!FIRCLSContextInitialize(report, self.settings, _fileManager)) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setupStateNotifications];
|
[self.notificationManager registerNotificationListener];
|
||||||
|
|
||||||
[self registerAnalyticsEventListener];
|
[self.analyticsManager registerAnalyticsListener];
|
||||||
|
|
||||||
[self crashReportingSetupCompleted:mark];
|
[self crashReportingSetupCompleted:mark];
|
||||||
|
|
||||||
|
@ -507,7 +385,9 @@ static void (^reportSentCallback)(void);
|
||||||
// check our handlers
|
// check our handlers
|
||||||
FIRCLSDispatchAfter(2.0, dispatch_get_main_queue(), ^{
|
FIRCLSDispatchAfter(2.0, dispatch_get_main_queue(), ^{
|
||||||
FIRCLSExceptionCheckHandlers((__bridge void *)(self));
|
FIRCLSExceptionCheckHandlers((__bridge void *)(self));
|
||||||
|
#if CLS_SIGNAL_SUPPORTED
|
||||||
FIRCLSSignalCheckHandlers();
|
FIRCLSSignalCheckHandlers();
|
||||||
|
#endif
|
||||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||||
FIRCLSMachExceptionCheckHandlers();
|
FIRCLSMachExceptionCheckHandlers();
|
||||||
#endif
|
#endif
|
||||||
|
@ -515,7 +395,7 @@ static void (^reportSentCallback)(void);
|
||||||
|
|
||||||
// remove the launch failure marker and record the startup time
|
// remove the launch failure marker and record the startup time
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self removeLaunchFailureMarker];
|
[self.launchMarker removeLaunchFailureMarker];
|
||||||
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
||||||
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSFirstRunloopTurnTimeKey,
|
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSFirstRunloopTurnTimeKey,
|
||||||
[@(FIRCLSProfileEnd(mark)) description]);
|
[@(FIRCLSProfileEnd(mark)) description]);
|
||||||
|
@ -542,26 +422,24 @@ static void (^reportSentCallback)(void);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([self.dataArbiter isLegacyDataCollectionKeyInPlist]) {
|
||||||
|
FIRCLSErrorLog(@"Found legacy data collection key in app's Info.plist: "
|
||||||
|
@"firebase_crashlytics_collection_enabled");
|
||||||
|
FIRCLSErrorLog(@"Please update your Info.plist to use the new data collection key: "
|
||||||
|
@"FirebaseCrashlyticsCollectionEnabled");
|
||||||
|
FIRCLSErrorLog(@"The legacy data collection Info.plist value could be overridden by "
|
||||||
|
@"calling: [Fabric with:...]");
|
||||||
|
FIRCLSErrorLog(@"The new value can be overridden by calling: [[FIRCrashlytics "
|
||||||
|
@"crashlytics] setCrashlyticsCollectionEnabled:<isEnabled>]");
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FIRCLSReportUploader *)uploader {
|
|
||||||
if (!_uploader) {
|
|
||||||
_uploader = [[FIRCLSReportUploader alloc] initWithQueue:self.operationQueue
|
|
||||||
delegate:self
|
|
||||||
dataSource:self
|
|
||||||
client:self.networkClient
|
|
||||||
fileManager:_fileManager
|
|
||||||
analytics:_analytics];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _uploader;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Reporting Lifecycle
|
|
||||||
|
|
||||||
- (FIRCLSInternalReport *)setupCurrentReport:(NSString *)executionIdentifier {
|
- (FIRCLSInternalReport *)setupCurrentReport:(NSString *)executionIdentifier {
|
||||||
[self createLaunchFailureMarker];
|
[self.launchMarker createLaunchFailureMarker];
|
||||||
|
|
||||||
NSString *reportPath = [_fileManager setupNewPathForExecutionIdentifier:executionIdentifier];
|
NSString *reportPath = [_fileManager setupNewPathForExecutionIdentifier:executionIdentifier];
|
||||||
|
|
||||||
|
@ -569,341 +447,4 @@ static void (^reportSentCallback)(void);
|
||||||
executionIdentifier:executionIdentifier];
|
executionIdentifier:executionIdentifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)countSubmittableAndDeleteUnsubmittableReportPaths:(NSArray *)reportPaths {
|
|
||||||
int count = 0;
|
|
||||||
for (NSString *path in reportPaths) {
|
|
||||||
FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
|
|
||||||
if ([report needsToBeSubmitted]) {
|
|
||||||
count++;
|
|
||||||
} else {
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
[self->_fileManager removeItemAtPath:path];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)processExistingReportPaths:(NSArray *)reportPaths
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
|
||||||
asUrgent:(BOOL)urgent {
|
|
||||||
for (NSString *path in reportPaths) {
|
|
||||||
[self processExistingActiveReportPath:path
|
|
||||||
dataCollectionToken:dataCollectionToken
|
|
||||||
asUrgent:urgent];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)processExistingActiveReportPath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
|
||||||
asUrgent:(BOOL)urgent {
|
|
||||||
FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
|
|
||||||
|
|
||||||
// TODO: needsToBeSubmitted should really be called on the background queue.
|
|
||||||
if (![report needsToBeSubmitted]) {
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
[self->_fileManager removeItemAtPath:path];
|
|
||||||
}];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urgent && [dataCollectionToken isValid]) {
|
|
||||||
// We can proceed without the delegate.
|
|
||||||
[[self uploader] prepareAndSubmitReport:report
|
|
||||||
dataCollectionToken:dataCollectionToken
|
|
||||||
asUrgent:urgent
|
|
||||||
withProcessing:YES];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self submitReport:report dataCollectionToken:dataCollectionToken];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)submitReport:(FIRCLSInternalReport *)report
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken {
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
[[self uploader] prepareAndSubmitReport:report
|
|
||||||
dataCollectionToken:dataCollectionToken
|
|
||||||
asUrgent:NO
|
|
||||||
withProcessing:YES];
|
|
||||||
}];
|
|
||||||
|
|
||||||
[self didSubmitReport];
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the side-effect of calling deleteUnsentReports, or collect_reports setting
|
|
||||||
// being false
|
|
||||||
- (void)deleteUnsentReportsWithPreexisting:(NSArray *)preexistingReportPaths {
|
|
||||||
[self removeExistingReportPaths:preexistingReportPaths];
|
|
||||||
|
|
||||||
[self removeExistingReportPaths:self.fileManager.processingPathContents];
|
|
||||||
if (self.settings.shouldUseNewReportEndpoint) {
|
|
||||||
[self removeExistingReportPaths:self.fileManager.preparedPathContents];
|
|
||||||
} else {
|
|
||||||
[self removeExistingReportPaths:self.fileManager.legacyPreparedPathContents];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)removeExistingReportPaths:(NSArray *)reportPaths {
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
for (NSString *path in reportPaths) {
|
|
||||||
[self.fileManager removeItemAtPath:path];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handleContentsInOtherReportingDirectoriesWithToken:(FIRCLSDataCollectionToken *)token {
|
|
||||||
[self handleExistingFilesInProcessingWithToken:token];
|
|
||||||
[self handleExistingFilesInPreparedWithToken:token];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handleExistingFilesInProcessingWithToken:(FIRCLSDataCollectionToken *)token {
|
|
||||||
NSArray *processingPaths = _fileManager.processingPathContents;
|
|
||||||
|
|
||||||
// deal with stuff in processing more carefully - do not process again
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
for (NSString *path in processingPaths) {
|
|
||||||
FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
|
|
||||||
[[self uploader] prepareAndSubmitReport:report
|
|
||||||
dataCollectionToken:token
|
|
||||||
asUrgent:NO
|
|
||||||
withProcessing:NO];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handleExistingFilesInPreparedWithToken:(FIRCLSDataCollectionToken *)token {
|
|
||||||
NSArray *preparedPaths = self.settings.shouldUseNewReportEndpoint
|
|
||||||
? _fileManager.preparedPathContents
|
|
||||||
: _fileManager.legacyPreparedPathContents;
|
|
||||||
|
|
||||||
// Give our network client a chance to reconnect here, if needed. This attempts to avoid
|
|
||||||
// trying to re-submit a prepared file that is already in flight.
|
|
||||||
[self.networkClient attemptToReconnectBackgroundSessionWithCompletionBlock:^{
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
[self uploadPreexistingFiles:preparedPaths withToken:token];
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)uploadPreexistingFiles:(NSArray *)files withToken:(FIRCLSDataCollectionToken *)token {
|
|
||||||
// Because this could happen quite a bit after the inital set of files was
|
|
||||||
// captured, some could be completed (deleted). So, just double-check to make sure
|
|
||||||
// the file still exists.
|
|
||||||
|
|
||||||
for (NSString *path in files) {
|
|
||||||
if (![[_fileManager underlyingFileManager] fileExistsAtPath:path]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[self uploader] uploadPackagedReportAtPath:path dataCollectionToken:token asUrgent:NO];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)retryUploadForReportAtPath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)token {
|
|
||||||
FIRCLSAddOperationAfter(CLSReportRetryInterval, self.operationQueue, ^{
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash", @"re-attempting report submission");
|
|
||||||
[[self uploader] uploadPackagedReportAtPath:path dataCollectionToken:token asUrgent:NO];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Launch Failure Detection
|
|
||||||
- (NSString *)launchFailureMarkerPath {
|
|
||||||
return [[_fileManager structurePath] stringByAppendingPathComponent:@"launchmarker"];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)createLaunchFailureMarker {
|
|
||||||
// It's tempting to use - [NSFileManger createFileAtPath:contents:attributes:] here. But that
|
|
||||||
// operation, even with empty/nil contents does a ton of work to write out nothing via a
|
|
||||||
// temporarly file. This is a much faster implemenation.
|
|
||||||
const char *path = [[self launchFailureMarkerPath] fileSystemRepresentation];
|
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
|
||||||
/*
|
|
||||||
* data-protected non-portable open(2) :
|
|
||||||
* int open_dprotected_np(user_addr_t path, int flags, int class, int dpflags, int mode)
|
|
||||||
*/
|
|
||||||
int fd = open_dprotected_np(path, O_WRONLY | O_CREAT | O_TRUNC, 4, 0, 0644);
|
|
||||||
#else
|
|
||||||
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
||||||
#endif
|
|
||||||
if (fd == -1) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return close(fd) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)launchFailureMarkerPresent {
|
|
||||||
return [[_fileManager underlyingFileManager] fileExistsAtPath:[self launchFailureMarkerPath]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)removeLaunchFailureMarker {
|
|
||||||
return [_fileManager removeItemAtPath:[self launchFailureMarkerPath]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)checkForAndCreateLaunchMarker {
|
|
||||||
BOOL launchFailure = [self launchFailureMarkerPresent];
|
|
||||||
if (launchFailure) {
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash",
|
|
||||||
@"Last launch failed: this may indicate a crash shortly after app launch.");
|
|
||||||
} else {
|
|
||||||
[self createLaunchFailureMarker];
|
|
||||||
}
|
|
||||||
|
|
||||||
return launchFailure;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
|
|
||||||
- (void)registerAnalyticsEventListener {
|
|
||||||
if (_registeredAnalyticsEventListener) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FIRCLSAnalyticsInteropListener *listener = [[FIRCLSAnalyticsInteropListener alloc] init];
|
|
||||||
[FIRCLSFCRAnalytics registerEventListener:listener toAnalytics:_analytics];
|
|
||||||
_registeredAnalyticsEventListener = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Notifications
|
|
||||||
- (void)setupStateNotifications {
|
|
||||||
[self captureInitialNotificationStates];
|
|
||||||
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(willBecomeActive:)
|
|
||||||
name:UIApplicationWillEnterForegroundNotification
|
|
||||||
object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(didBecomeInactive:)
|
|
||||||
name:UIApplicationDidEnterBackgroundNotification
|
|
||||||
object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(didChangeOrientation:)
|
|
||||||
name:UIDeviceOrientationDidChangeNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
addObserver:self
|
|
||||||
selector:@selector(didChangeUIOrientation:)
|
|
||||||
name:UIApplicationDidChangeStatusBarOrientationNotification
|
|
||||||
object:nil];
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
#elif CLS_TARGET_OS_OSX
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(willBecomeActive:)
|
|
||||||
name:@"NSApplicationWillBecomeActiveNotification"
|
|
||||||
object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(didBecomeInactive:)
|
|
||||||
name:@"NSApplicationDidResignActiveNotification"
|
|
||||||
object:nil];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)captureInitialNotificationStates {
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
|
|
||||||
UIInterfaceOrientation statusBarOrientation =
|
|
||||||
[FIRCLSApplicationSharedInstance() statusBarOrientation];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// It's nice to do this async, so we don't hold up the main thread while doing three
|
|
||||||
// consecutive IOs here.
|
|
||||||
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
|
||||||
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSInBackgroundKey, @"0");
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSDeviceOrientationKey,
|
|
||||||
[@(orientation) description]);
|
|
||||||
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSUIOrientationKey,
|
|
||||||
[@(statusBarOrientation) description]);
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)willBecomeActive:(NSNotification *)notification {
|
|
||||||
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @NO);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)didBecomeInactive:(NSNotification *)notification {
|
|
||||||
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @YES);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TARGET_OS_IOS
|
|
||||||
- (void)didChangeOrientation:(NSNotification *)notification {
|
|
||||||
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
|
|
||||||
|
|
||||||
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDeviceOrientationKey, @(orientation));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)didChangeUIOrientation:(NSNotification *)notification {
|
|
||||||
UIInterfaceOrientation statusBarOrientation =
|
|
||||||
[FIRCLSApplicationSharedInstance() statusBarOrientation];
|
|
||||||
|
|
||||||
FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSUIOrientationKey, @(statusBarOrientation));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma mark - FIRCLSNetworkClientDelegate
|
|
||||||
- (BOOL)networkClientCanUseBackgroundSessions:(FIRCLSNetworkClient *)client {
|
|
||||||
return !FIRCLSApplicationIsExtension();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)networkClient:(FIRCLSNetworkClient *)client
|
|
||||||
didFinishUploadWithPath:(NSString *)path
|
|
||||||
error:(NSError *)error {
|
|
||||||
// Route this through to the reports uploader.
|
|
||||||
// Since this callback happens after an upload finished, then we can assume that the original data
|
|
||||||
// collection was authorized. This isn't ideal, but it's better than trying to plumb the data
|
|
||||||
// collection token through all the system networking callbacks.
|
|
||||||
FIRCLSDataCollectionToken *token = [FIRCLSDataCollectionToken validToken];
|
|
||||||
[[self uploader] reportUploadAtPath:path dataCollectionToken:token completedWithError:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - FIRCLSReportUploaderDelegate
|
|
||||||
|
|
||||||
- (void)didCompletePackageSubmission:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)token
|
|
||||||
error:(NSError *)error {
|
|
||||||
if (!error) {
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash", @"report submission successful");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash", @"report submission failed with error %@", error);
|
|
||||||
FIRCLSSDKLog("Error: failed to submit report '%s'\n", error.description.UTF8String);
|
|
||||||
|
|
||||||
[self retryUploadForReportAtPath:path dataCollectionToken:token];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)didCompleteAllSubmissions {
|
|
||||||
[self.operationQueue addOperationWithBlock:^{
|
|
||||||
// Dealloc the reports uploader. If we need it again (if we re-enqueued submissions from
|
|
||||||
// didCompletePackageSubmission:, we can just create it again
|
|
||||||
self->_uploader = nil;
|
|
||||||
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash", @"report submission complete");
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - UITest Helpers
|
|
||||||
|
|
||||||
// Used only for internal data collection E2E testing
|
|
||||||
- (void)didSubmitReport {
|
|
||||||
if (reportSentCallback) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
reportSentCallback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)setReportSentCallback:(void (^)(void))callback {
|
|
||||||
reportSentCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -12,24 +12,22 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FIRCLSReportManager.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h"
|
||||||
#import "FIRCLSReportUploader.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
|
||||||
|
#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h"
|
||||||
|
|
||||||
@class FIRCLSInstallIdentifierModel;
|
@class FIRCLSInstallIdentifierModel;
|
||||||
|
|
||||||
@interface FIRCLSReportManager () <FIRCLSReportUploaderDelegate, FIRCLSReportUploaderDataSource>
|
@interface FIRCLSReportManager ()
|
||||||
|
|
||||||
@property(nonatomic, strong) NSOperationQueue *operationQueue;
|
@property(nonatomic, strong) NSOperationQueue *operationQueue;
|
||||||
@property(nonatomic, strong) FIRCLSNetworkClient *networkClient;
|
|
||||||
@property(nonatomic, readonly) FIRCLSReportUploader *uploader;
|
|
||||||
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
|
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface FIRCLSReportManager (PrivateMethods)
|
@interface FIRCLSReportManager (PrivateMethods)
|
||||||
|
|
||||||
- (BOOL)createLaunchFailureMarker;
|
@property(nonatomic, strong) FIRCLSLaunchMarkerModel *launchMarker;
|
||||||
- (BOOL)launchFailureMarkerPresent;
|
|
||||||
|
|
||||||
- (BOOL)potentiallySubmittableCrashOccurred;
|
- (BOOL)potentiallySubmittableCrashOccurred;
|
||||||
|
|
||||||
|
|
|
@ -14,67 +14,27 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
|
||||||
|
|
||||||
@class FIRCLSDataCollectionToken;
|
@class FIRCLSDataCollectionToken;
|
||||||
@class FIRCLSInternalReport;
|
@class FIRCLSInternalReport;
|
||||||
@class FIRCLSSettings;
|
@class FIRCLSManagerData;
|
||||||
@class FIRCLSFileManager;
|
@class FIRCLSFileManager;
|
||||||
@class FIRCLSNetworkClient;
|
|
||||||
@class FIRCLSReportUploader;
|
|
||||||
|
|
||||||
@protocol FIRCLSReportUploaderDelegate;
|
|
||||||
@protocol FIRCLSReportUploaderDataSource;
|
|
||||||
@protocol FIRAnalyticsInterop;
|
|
||||||
|
|
||||||
@interface FIRCLSReportUploader : NSObject
|
@interface FIRCLSReportUploader : NSObject
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
- (instancetype)initWithQueue:(NSOperationQueue *)queue
|
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData NS_DESIGNATED_INITIALIZER;
|
||||||
delegate:(id<FIRCLSReportUploaderDelegate>)delegate
|
|
||||||
dataSource:(id<FIRCLSReportUploaderDataSource>)dataSource
|
|
||||||
client:(FIRCLSNetworkClient *)client
|
|
||||||
fileManager:(FIRCLSFileManager *)fileManager
|
|
||||||
analytics:(id<FIRAnalyticsInterop>)analytics NS_DESIGNATED_INITIALIZER;
|
|
||||||
|
|
||||||
@property(nonatomic, weak) id<FIRCLSReportUploaderDelegate> delegate;
|
|
||||||
@property(nonatomic, weak) id<FIRCLSReportUploaderDataSource> dataSource;
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) NSOperationQueue *operationQueue;
|
@property(nonatomic, readonly) NSOperationQueue *operationQueue;
|
||||||
@property(nonatomic, readonly) FIRCLSNetworkClient *networkClient;
|
|
||||||
@property(nonatomic, readonly) FIRCLSFileManager *fileManager;
|
@property(nonatomic, readonly) FIRCLSFileManager *fileManager;
|
||||||
|
|
||||||
- (BOOL)prepareAndSubmitReport:(FIRCLSInternalReport *)report
|
- (void)prepareAndSubmitReport:(FIRCLSInternalReport *)report
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
asUrgent:(BOOL)urgent
|
asUrgent:(BOOL)urgent
|
||||||
withProcessing:(BOOL)shouldProcess;
|
withProcessing:(BOOL)shouldProcess;
|
||||||
|
|
||||||
- (BOOL)uploadPackagedReportAtPath:(NSString *)path
|
- (void)uploadPackagedReportAtPath:(NSString *)path
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
asUrgent:(BOOL)urgent;
|
asUrgent:(BOOL)urgent;
|
||||||
|
|
||||||
- (void)reportUploadAtPath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
|
||||||
completedWithError:(NSError *)error;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@protocol FIRCLSReportUploaderDelegate <NSObject>
|
|
||||||
@required
|
|
||||||
|
|
||||||
- (void)didCompletePackageSubmission:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)token
|
|
||||||
error:(NSError *)error;
|
|
||||||
- (void)didCompleteAllSubmissions;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@protocol FIRCLSReportUploaderDataSource <NSObject>
|
|
||||||
@required
|
|
||||||
|
|
||||||
- (NSString *)googleAppID;
|
|
||||||
- (FIRCLSSettings *)settings;
|
|
||||||
- (GDTCORTransport *)googleTransport;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -14,81 +14,89 @@
|
||||||
|
|
||||||
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
||||||
|
|
||||||
#import "FIRCLSApplication.h"
|
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||||
#import "FIRCLSDataCollectionArbiter.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
|
||||||
#import "FIRCLSDataCollectionToken.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
|
||||||
#import "FIRCLSDefines.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h"
|
||||||
#import "FIRCLSFCRAnalytics.h"
|
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||||
#import "FIRCLSFileManager.h"
|
#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||||
#import "FIRCLSInstallIdentifierModel.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||||
#import "FIRCLSInternalReport.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||||
#import "FIRCLSNetworkClient.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||||
#import "FIRCLSPackageReportOperation.h"
|
#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h"
|
||||||
#import "FIRCLSProcessReportOperation.h"
|
#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h"
|
||||||
#import "FIRCLSReportAdapter.h"
|
#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h"
|
||||||
#import "FIRCLSReportUploader_Private.h"
|
|
||||||
#import "FIRCLSSettings.h"
|
|
||||||
#import "FIRCLSSymbolResolver.h"
|
|
||||||
|
|
||||||
#include "FIRCLSUtility.h"
|
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||||
|
|
||||||
#import "FIRCLSConstants.h"
|
#import "Crashlytics/Shared/FIRCLSConstants.h"
|
||||||
#import "FIRCLSMultipartMimeStreamEncoder.h"
|
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSMultipartMimeStreamEncoder.h"
|
||||||
#import "FIRCLSURLBuilder.h"
|
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h"
|
||||||
|
|
||||||
#import <GoogleDataTransport/GDTCOREvent.h>
|
#import <GoogleDataTransport/GoogleDataTransport.h>
|
||||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
|
||||||
|
|
||||||
@interface FIRCLSReportUploader () {
|
@interface FIRCLSReportUploader () {
|
||||||
id<FIRAnalyticsInterop> _analytics;
|
id<FIRAnalyticsInterop> _analytics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
||||||
|
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) NSString *googleAppID;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation FIRCLSReportUploader
|
@implementation FIRCLSReportUploader
|
||||||
|
|
||||||
- (instancetype)initWithQueue:(NSOperationQueue *)queue
|
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData {
|
||||||
delegate:(id<FIRCLSReportUploaderDelegate>)delegate
|
|
||||||
dataSource:(id<FIRCLSReportUploaderDataSource>)dataSource
|
|
||||||
client:(FIRCLSNetworkClient *)client
|
|
||||||
fileManager:(FIRCLSFileManager *)fileManager
|
|
||||||
analytics:(id<FIRAnalyticsInterop>)analytics {
|
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
_operationQueue = queue;
|
_operationQueue = managerData.operationQueue;
|
||||||
_delegate = delegate;
|
_googleAppID = managerData.googleAppID;
|
||||||
_dataSource = dataSource;
|
_googleTransport = managerData.googleTransport;
|
||||||
_networkClient = client;
|
_installIDModel = managerData.installIDModel;
|
||||||
_fileManager = fileManager;
|
_fileManager = managerData.fileManager;
|
||||||
_analytics = analytics;
|
_analytics = managerData.analytics;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Packaging and Submission
|
#pragma mark - Packaging and Submission
|
||||||
- (BOOL)prepareAndSubmitReport:(FIRCLSInternalReport *)report
|
|
||||||
|
/*
|
||||||
|
* For a crash report, this is the inital code path for uploading. A report
|
||||||
|
* will not repeat this code path after it's happened because this code path
|
||||||
|
* will move the report from the "active" folder into "processing" and then
|
||||||
|
* "prepared". Once in prepared, the report can be re-uploaded any number of times
|
||||||
|
* with uploadPackagedReportAtPath in the case of an upload failure.
|
||||||
|
*/
|
||||||
|
- (void)prepareAndSubmitReport:(FIRCLSInternalReport *)report
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
asUrgent:(BOOL)urgent
|
asUrgent:(BOOL)urgent
|
||||||
withProcessing:(BOOL)shouldProcess {
|
withProcessing:(BOOL)shouldProcess {
|
||||||
__block BOOL success = NO;
|
|
||||||
|
|
||||||
if (![dataCollectionToken isValid]) {
|
if (![dataCollectionToken isValid]) {
|
||||||
FIRCLSErrorLog(@"Data collection disabled and report will not be submitted");
|
FIRCLSErrorLog(@"Data collection disabled and report will not be submitted");
|
||||||
return NO;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.dataSource.settings.orgID && !self.dataSource.settings.shouldUseNewReportEndpoint) {
|
|
||||||
FIRCLSDebugLog(
|
|
||||||
@"Skipping report with id '%@' this run of the app because Organization ID was "
|
|
||||||
@"nil. Report via the legacy endpoint will upload once settings are download successfully",
|
|
||||||
report.identifier);
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This activity is still relevant using GoogleDataTransport because the on-device
|
||||||
|
// symbolication operation may be computationally intensive.
|
||||||
FIRCLSApplicationActivity(
|
FIRCLSApplicationActivity(
|
||||||
FIRCLSApplicationActivityDefault, @"Crashlytics Crash Report Processing", ^{
|
FIRCLSApplicationActivityDefault, @"Crashlytics Crash Report Processing", ^{
|
||||||
|
// Run this only once because it can be run multiple times in succession,
|
||||||
|
// and if it's slow it could delay crash upload too much without providing
|
||||||
|
// user benefit.
|
||||||
|
static dispatch_once_t regenerateOnceToken;
|
||||||
|
dispatch_once(®enerateOnceToken, ^{
|
||||||
|
// Check to see if the FID has rotated before we construct the payload
|
||||||
|
// so that the payload has an updated value.
|
||||||
|
[self.installIDModel regenerateInstallIDIfNeeded];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run on-device symbolication before packaging if we should process
|
||||||
if (shouldProcess) {
|
if (shouldProcess) {
|
||||||
if (![self.fileManager moveItemAtPath:report.path
|
if (![self.fileManager moveItemAtPath:report.path
|
||||||
toDirectory:self.fileManager.processingPath]) {
|
toDirectory:self.fileManager.processingPath]) {
|
||||||
|
@ -108,165 +116,101 @@
|
||||||
[processOperation start];
|
[processOperation start];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *packagedPath;
|
|
||||||
|
|
||||||
FIRCLSDebugLog(@"Preparing the report for the new endpoint: %d",
|
|
||||||
self.dataSource.settings.shouldUseNewReportEndpoint);
|
|
||||||
|
|
||||||
// With the new report endpoint, the report is deleted once it is written to GDT
|
// With the new report endpoint, the report is deleted once it is written to GDT
|
||||||
// Check if the report has a crash file before the report is moved or deleted
|
// Check if the report has a crash file before the report is moved or deleted
|
||||||
BOOL isCrash = report.isCrash;
|
BOOL isCrash = report.isCrash;
|
||||||
|
|
||||||
if (self.dataSource.settings.shouldUseNewReportEndpoint) {
|
// For the new endpoint, just move the .clsrecords from "processing" -> "prepared".
|
||||||
// For the new endpoint, just move the .clsrecords from "processing" -> "prepared"
|
// In the old endpoint this was for packaging the report as a multipartmime file,
|
||||||
if (![self.fileManager moveItemAtPath:report.path
|
// so this can probably be removed for GoogleDataTransport.
|
||||||
toDirectory:self.fileManager.preparedPath]) {
|
if (![self.fileManager moveItemAtPath:report.path
|
||||||
FIRCLSErrorLog(@"Unable to move report to prepared");
|
toDirectory:self.fileManager.preparedPath]) {
|
||||||
return;
|
FIRCLSErrorLog(@"Unable to move report to prepared");
|
||||||
}
|
return;
|
||||||
|
|
||||||
packagedPath = [self.fileManager.preparedPath
|
|
||||||
stringByAppendingPathComponent:report.path.lastPathComponent];
|
|
||||||
} else {
|
|
||||||
// For the legacy endpoint, continue generate the multipartmime file in "prepared-legacy"
|
|
||||||
FIRCLSPackageReportOperation *packageOperation =
|
|
||||||
[[FIRCLSPackageReportOperation alloc] initWithReport:report
|
|
||||||
fileManager:self.fileManager
|
|
||||||
settings:self.dataSource.settings];
|
|
||||||
|
|
||||||
[packageOperation start];
|
|
||||||
packagedPath = packageOperation.finalPath;
|
|
||||||
if (!packagedPath) {
|
|
||||||
FIRCLSErrorLog(@"Unable to package report");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![self.fileManager removeItemAtPath:report.path]) {
|
|
||||||
FIRCLSErrorLog(@"Unable to remove a processing item");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NSLog(@"[Firebase/Crashlytics] Packaged report with id '%@' for submission",
|
NSString *packagedPath = [self.fileManager.preparedPath
|
||||||
report.identifier);
|
stringByAppendingPathComponent:report.path.lastPathComponent];
|
||||||
|
|
||||||
success = [self uploadPackagedReportAtPath:packagedPath
|
FIRCLSInfoLog(@"[Firebase/Crashlytics] Packaged report with id '%@' for submission",
|
||||||
dataCollectionToken:dataCollectionToken
|
report.identifier);
|
||||||
asUrgent:urgent];
|
|
||||||
|
|
||||||
// If the upload was successful and the report contained a crash forward it to Google
|
[self uploadPackagedReportAtPath:packagedPath
|
||||||
// Analytics.
|
dataCollectionToken:dataCollectionToken
|
||||||
if (success && isCrash) {
|
asUrgent:urgent];
|
||||||
[FIRCLSFCRAnalytics logCrashWithTimeStamp:report.crashedOnDate.timeIntervalSince1970
|
|
||||||
toAnalytics:self->_analytics];
|
// We don't check for success here for 2 reasons:
|
||||||
|
// 1) If we can't upload a crash for whatever reason, but we can upload analytics
|
||||||
|
// it's better for the customer to get accurate Crash Free Users.
|
||||||
|
// 2) In the past we did try to check for success, but it was a useless check because
|
||||||
|
// sendDataEvent is async (unless we're sending urgently).
|
||||||
|
if (isCrash) {
|
||||||
|
[FIRCLSAnalyticsManager logCrashWithTimeStamp:report.crashedOnDate.timeIntervalSince1970
|
||||||
|
toAnalytics:self->_analytics];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return success;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)submitPackageMultipartMimeAtPath:(NSString *)multipartmimePath
|
/*
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
* This code path can be repeated any number of times for a prepared crash report if
|
||||||
synchronously:(BOOL)synchronous {
|
* the report is failing to upload.
|
||||||
FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports", "Submitting %@ %@",
|
*
|
||||||
synchronous ? @"sync" : @"async", multipartmimePath);
|
* Therefore, side effects (like logging to Analytics) should not go in this method or
|
||||||
|
* else they will re-trigger when failures happen.
|
||||||
if ([[[self fileManager] fileSizeAtPath:multipartmimePath] unsignedIntegerValue] == 0) {
|
*
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports", @"Already-submitted report being ignored");
|
* When a crash report fails to upload, it will stay in the "prepared" folder. Upon next
|
||||||
return NO;
|
* run of the app, the ReportManager will attempt to re-upload prepared reports using this
|
||||||
}
|
* method.
|
||||||
|
*/
|
||||||
NSTimeInterval timeout = 10.0;
|
- (void)uploadPackagedReportAtPath:(NSString *)path
|
||||||
|
|
||||||
// If we are submitting synchronously, be more aggressive with the timeout. However,
|
|
||||||
// we only need this if the client does not support background requests.
|
|
||||||
if (synchronous && ![[self networkClient] supportsBackgroundRequests]) {
|
|
||||||
timeout = 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableURLRequest *request = [self mutableRequestWithURL:[self reportURL] timeout:timeout];
|
|
||||||
|
|
||||||
[request setHTTPMethod:@"POST"];
|
|
||||||
|
|
||||||
if (![self fillInRequest:request forMultipartMimeDataAtPath:multipartmimePath]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[self networkClient] startUploadRequest:request
|
|
||||||
filePath:multipartmimePath
|
|
||||||
dataCollectionToken:dataCollectionToken
|
|
||||||
immediately:synchronous];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)uploadPackagedReportAtPath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||||
asUrgent:(BOOL)urgent {
|
asUrgent:(BOOL)urgent {
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports", @"Submitting report%@",
|
FIRCLSDebugLog(@"Submitting report %@", urgent ? @"urgently" : @"async");
|
||||||
urgent ? @" as urgent" : @"");
|
|
||||||
|
|
||||||
// Check with the legacy path as the new path will always be contained in the legacy path
|
if (![dataCollectionToken isValid]) {
|
||||||
BOOL isNewPreparedPath = ![path containsString:self.fileManager.legacyPreparedPath];
|
FIRCLSErrorLog(@"A report upload was requested with an invalid data collection token.");
|
||||||
|
return;
|
||||||
if (isNewPreparedPath && self.dataSource.settings.shouldUseNewReportEndpoint) {
|
|
||||||
if (![dataCollectionToken isValid]) {
|
|
||||||
FIRCLSErrorLog(@"A report upload was requested with an invalid data collection token.");
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
FIRCLSReportAdapter *adapter =
|
|
||||||
[[FIRCLSReportAdapter alloc] initWithPath:path googleAppId:self.dataSource.googleAppID];
|
|
||||||
|
|
||||||
GDTCOREvent *event = [self.dataSource.googleTransport eventForTransport];
|
|
||||||
event.dataObject = adapter;
|
|
||||||
event.qosTier = GDTCOREventQoSFast; // Bypass batching, send immediately
|
|
||||||
|
|
||||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
||||||
|
|
||||||
__block BOOL success = YES;
|
|
||||||
|
|
||||||
[self.dataSource.googleTransport
|
|
||||||
sendDataEvent:event
|
|
||||||
onComplete:^(BOOL wasWritten, NSError *error) {
|
|
||||||
if (!wasWritten) {
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports",
|
|
||||||
@"Failed to send crash report due to gdt write failure.");
|
|
||||||
success = NO;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports",
|
|
||||||
@"Failed to send crash report due to gdt error: %@",
|
|
||||||
error.localizedDescription);
|
|
||||||
success = NO;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports",
|
|
||||||
@"Completed report submission with id: %@", path.lastPathComponent);
|
|
||||||
|
|
||||||
if (urgent) {
|
|
||||||
dispatch_semaphore_signal(semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
[self cleanUpSubmittedReportAtPath:path];
|
|
||||||
}];
|
|
||||||
|
|
||||||
if (urgent) {
|
|
||||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
|
|
||||||
} else if (!isNewPreparedPath && !self.dataSource.settings.shouldUseNewReportEndpoint) {
|
|
||||||
return [self submitPackageMultipartMimeAtPath:path
|
|
||||||
dataCollectionToken:dataCollectionToken
|
|
||||||
synchronously:urgent];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsupported state
|
FIRCLSReportAdapter *adapter = [[FIRCLSReportAdapter alloc] initWithPath:path
|
||||||
return NO;
|
googleAppId:self.googleAppID
|
||||||
|
installIDModel:self.installIDModel];
|
||||||
|
|
||||||
|
GDTCOREvent *event = [self.googleTransport eventForTransport];
|
||||||
|
event.dataObject = adapter;
|
||||||
|
event.qosTier = GDTCOREventQoSFast; // Bypass batching, send immediately
|
||||||
|
|
||||||
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||||
|
|
||||||
|
[self.googleTransport
|
||||||
|
sendDataEvent:event
|
||||||
|
onComplete:^(BOOL wasWritten, NSError *error) {
|
||||||
|
if (!wasWritten) {
|
||||||
|
FIRCLSErrorLog(
|
||||||
|
@"Failed to send crash report due to failure writing GoogleDataTransport event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
FIRCLSErrorLog(@"Failed to send crash report due to GoogleDataTransport error: %@",
|
||||||
|
error.localizedDescription);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRCLSInfoLog(@"Completed report submission with id: %@", path.lastPathComponent);
|
||||||
|
|
||||||
|
if (urgent) {
|
||||||
|
dispatch_semaphore_signal(semaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self cleanUpSubmittedReportAtPath:path];
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (urgent) {
|
||||||
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)cleanUpSubmittedReportAtPath:(NSString *)path {
|
- (BOOL)cleanUpSubmittedReportAtPath:(NSString *)path {
|
||||||
|
@ -278,79 +222,4 @@
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reportUploadAtPath:(NSString *)path
|
|
||||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
|
||||||
completedWithError:(NSError *)error {
|
|
||||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports", @"completed submission of %@", path);
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
[self cleanUpSubmittedReportAtPath:path];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[self delegate] didCompletePackageSubmission:path
|
|
||||||
dataCollectionToken:dataCollectionToken
|
|
||||||
error:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Properties (TODO: Can delete once the experiment is over)
|
|
||||||
|
|
||||||
- (NSURL *)reportURL {
|
|
||||||
FIRCLSURLBuilder *url = [FIRCLSURLBuilder URLWithBase:FIRCLSReportsEndpoint];
|
|
||||||
|
|
||||||
[url appendComponent:@"/sdk-api/v1/platforms/"];
|
|
||||||
[url appendComponent:FIRCLSApplicationGetPlatform()];
|
|
||||||
[url appendComponent:@"/apps/"];
|
|
||||||
[url appendComponent:self.dataSource.settings.fetchedBundleID];
|
|
||||||
[url appendComponent:@"/reports"];
|
|
||||||
|
|
||||||
return [url URL];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)localeIdentifier {
|
|
||||||
return [[NSLocale currentLocale] localeIdentifier];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - URL Requests
|
|
||||||
- (NSMutableURLRequest *)mutableRequestWithURL:(NSURL *)url timeout:(NSTimeInterval)timeout {
|
|
||||||
NSMutableURLRequest *request =
|
|
||||||
[NSMutableURLRequest requestWithURL:url
|
|
||||||
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
|
|
||||||
timeoutInterval:timeout];
|
|
||||||
|
|
||||||
NSString *localeId = [self localeIdentifier];
|
|
||||||
|
|
||||||
[request setValue:@CLS_SDK_GENERATOR_NAME forHTTPHeaderField:FIRCLSNetworkUserAgent];
|
|
||||||
[request setValue:FIRCLSNetworkApplicationJson forHTTPHeaderField:FIRCLSNetworkAccept];
|
|
||||||
[request setValue:FIRCLSNetworkUTF8 forHTTPHeaderField:FIRCLSNetworkAcceptCharset];
|
|
||||||
[request setValue:localeId forHTTPHeaderField:FIRCLSNetworkAcceptLanguage];
|
|
||||||
[request setValue:localeId forHTTPHeaderField:FIRCLSNetworkContentLanguage];
|
|
||||||
[request setValue:FIRCLSDeveloperToken forHTTPHeaderField:FIRCLSNetworkCrashlyticsDeveloperToken];
|
|
||||||
[request setValue:FIRCLSApplicationGetSDKBundleID()
|
|
||||||
forHTTPHeaderField:FIRCLSNetworkCrashlyticsAPIClientId];
|
|
||||||
[request setValue:@CLS_SDK_DISPLAY_VERSION
|
|
||||||
forHTTPHeaderField:FIRCLSNetworkCrashlyticsAPIClientDisplayVersion];
|
|
||||||
[request setValue:[[self dataSource] googleAppID]
|
|
||||||
forHTTPHeaderField:FIRCLSNetworkCrashlyticsGoogleAppId];
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)fillInRequest:(NSMutableURLRequest *)request forMultipartMimeDataAtPath:(NSString *)path {
|
|
||||||
NSString *boundary = [[path lastPathComponent] stringByDeletingPathExtension];
|
|
||||||
|
|
||||||
[request setValue:[FIRCLSMultipartMimeStreamEncoder
|
|
||||||
contentTypeHTTPHeaderValueWithBoundary:boundary]
|
|
||||||
forHTTPHeaderField:@"Content-Type"];
|
|
||||||
|
|
||||||
NSNumber *fileSize = [[self fileManager] fileSizeAtPath:path];
|
|
||||||
if (fileSize == nil) {
|
|
||||||
FIRCLSErrorLog(@"Could not determine size of multipart mime file");
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
[request setValue:[fileSize stringValue] forHTTPHeaderField:@"Content-Length"];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FIRCLSReportUploader.h"
|
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
|
||||||
|
|
||||||
@interface FIRCLSReportUploader (PrivateMethods)
|
@interface FIRCLSReportUploader (PrivateMethods)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FIRCLSDataCollectionArbiter.h"
|
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
|
||||||
|
|
||||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||||
#import <FBLPromises/FBLPromises.h>
|
#import <FBLPromises/FBLPromises.h>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
|
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
|
||||||
|
|
||||||
#import "FIRCLSUserDefaults.h"
|
#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h"
|
||||||
|
|
||||||
// The legacy data collection setting allows Fabric customers to turn off auto-
|
// The legacy data collection setting allows Fabric customers to turn off auto-
|
||||||
// initialization, but can be overridden by calling [Fabric with:].
|
// initialization, but can be overridden by calling [Fabric with:].
|
||||||
|
@ -101,7 +101,6 @@ typedef NS_ENUM(NSInteger, FIRCLSDataCollectionSetting) {
|
||||||
[firebaseCrashlyticsCollectionEnabled isKindOfClass:[NSNumber class]]) {
|
[firebaseCrashlyticsCollectionEnabled isKindOfClass:[NSNumber class]]) {
|
||||||
return [firebaseCrashlyticsCollectionEnabled boolValue];
|
return [firebaseCrashlyticsCollectionEnabled boolValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [app isDataCollectionDefaultEnabled];
|
return [app isDataCollectionDefaultEnabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#import "FIRCLSDataCollectionToken.h"
|
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||||
|
|
||||||
@implementation FIRCLSDataCollectionToken
|
@implementation FIRCLSDataCollectionToken
|
||||||
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
// Copyright 2019 Google
|
|
||||||
//
|
|
||||||
// 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 "FIRCLSURLSessionAvailability.h"
|
|
||||||
|
|
||||||
#if FIRCLSURLSESSION_REQUIRED
|
|
||||||
|
|
||||||
#import "FIRCLSURLSessionConfiguration.h"
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface FIRCLSURLSession : NSObject {
|
|
||||||
id<NSURLSessionDelegate> _delegate;
|
|
||||||
NSOperationQueue *_delegateQueue;
|
|
||||||
NSURLSessionConfiguration *_configuration;
|
|
||||||
NSMutableSet *_taskSet;
|
|
||||||
dispatch_queue_t _queue;
|
|
||||||
|
|
||||||
NSString *_sessionDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL)NSURLSessionShouldBeUsed;
|
|
||||||
|
|
||||||
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
|
|
||||||
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
|
|
||||||
delegate:(nullable id<NSURLSessionDelegate>)delegate
|
|
||||||
delegateQueue:(nullable NSOperationQueue *)queue;
|
|
||||||
|
|
||||||
@property(nonatomic, readonly, retain) NSOperationQueue *delegateQueue;
|
|
||||||
@property(nonatomic, readonly, retain) id<NSURLSessionDelegate> delegate;
|
|
||||||
@property(nonatomic, readonly, copy) NSURLSessionConfiguration *configuration;
|
|
||||||
|
|
||||||
@property(nonatomic, copy) NSString *sessionDescription;
|
|
||||||
|
|
||||||
- (void)getTasksWithCompletionHandler:
|
|
||||||
(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler;
|
|
||||||
|
|
||||||
// task creation - suitable for background operations
|
|
||||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
|
|
||||||
|
|
||||||
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
|
|
||||||
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
|
|
||||||
|
|
||||||
// convenience methods (that are not available for background sessions
|
|
||||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
|
||||||
completionHandler:(nullable void (^)(NSData *data,
|
|
||||||
NSURLResponse *response,
|
|
||||||
NSError *error))completionHandler;
|
|
||||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
|
|
||||||
|
|
||||||
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
|
|
||||||
completionHandler:
|
|
||||||
(nullable void (^)(NSURL *targetPath,
|
|
||||||
NSURLResponse *response,
|
|
||||||
NSError *error))completionHandler;
|
|
||||||
|
|
||||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
|
||||||
fromFile:(NSURL *)fileURL
|
|
||||||
completionHandler:
|
|
||||||
(nullable void (^)(NSData *data,
|
|
||||||
NSURLResponse *response,
|
|
||||||
NSError *error))completionHandler;
|
|
||||||
|
|
||||||
- (void)invalidateAndCancel;
|
|
||||||
- (void)finishTasksAndInvalidate;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,346 +0,0 @@
|
||||||
// Copyright 2019 Google
|
|
||||||
//
|
|
||||||
// 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 "FIRCLSURLSessionAvailability.h"
|
|
||||||
|
|
||||||
#if FIRCLSURLSESSION_REQUIRED
|
|
||||||
#import "FIRCLSURLSession.h"
|
|
||||||
|
|
||||||
#import "FIRCLSURLSessionDataTask.h"
|
|
||||||
#import "FIRCLSURLSessionDataTask_PrivateMethods.h"
|
|
||||||
#import "FIRCLSURLSessionDownloadTask.h"
|
|
||||||
#import "FIRCLSURLSessionDownloadTask_PrivateMethods.h"
|
|
||||||
#import "FIRCLSURLSessionTask_PrivateMethods.h"
|
|
||||||
#import "FIRCLSURLSessionUploadTask.h"
|
|
||||||
|
|
||||||
#define DELEGATE ((id<NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>)self->_delegate)
|
|
||||||
|
|
||||||
@interface FIRCLSURLSession () <FIRCLSURLSessionDownloadDelegate>
|
|
||||||
|
|
||||||
@property(nonatomic, retain) NSOperationQueue *delegateQueue;
|
|
||||||
@property(nonatomic, retain) id<NSURLSessionDelegate> delegate;
|
|
||||||
@property(nonatomic, copy) NSURLSessionConfiguration *configuration;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation FIRCLSURLSession
|
|
||||||
|
|
||||||
@synthesize delegate = _delegate;
|
|
||||||
@synthesize delegateQueue = _delegateQueue;
|
|
||||||
@synthesize configuration = _configuration;
|
|
||||||
@synthesize sessionDescription = _sessionDescription;
|
|
||||||
|
|
||||||
+ (BOOL)NSURLSessionShouldBeUsed {
|
|
||||||
if (!NSClassFromString(@"NSURLSession")) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use this as a proxy to verify that we are on at least iOS 8 or 10.10. The first OSes that
|
|
||||||
// has NSURLSession were fairly unstable.
|
|
||||||
return [[NSURLSessionConfiguration class]
|
|
||||||
respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration {
|
|
||||||
return [self sessionWithConfiguration:configuration delegate:nil delegateQueue:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
|
|
||||||
delegate:(nullable id<NSURLSessionDelegate>)delegate
|
|
||||||
delegateQueue:(nullable NSOperationQueue *)queue {
|
|
||||||
if ([self NSURLSessionShouldBeUsed]) {
|
|
||||||
return [NSURLSession sessionWithConfiguration:configuration
|
|
||||||
delegate:delegate
|
|
||||||
delegateQueue:queue];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configuration) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __has_feature(objc_arc)
|
|
||||||
FIRCLSURLSession *session = [self new];
|
|
||||||
#else
|
|
||||||
FIRCLSURLSession *session = [[self new] autorelease];
|
|
||||||
#endif
|
|
||||||
[session setDelegate:delegate];
|
|
||||||
// When delegate exists, but delegateQueue is nil, create a serial queue like NSURLSession
|
|
||||||
// documents.
|
|
||||||
if (delegate && !queue) {
|
|
||||||
queue = [self newDefaultDelegateQueue];
|
|
||||||
}
|
|
||||||
session.delegateQueue = queue;
|
|
||||||
session.configuration = configuration;
|
|
||||||
return (NSURLSession *)session;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSOperationQueue *)newDefaultDelegateQueue {
|
|
||||||
NSOperationQueue *delegateQueue = [[NSOperationQueue alloc] init];
|
|
||||||
delegateQueue.name = [NSString stringWithFormat:@"%@ %p", NSStringFromClass(self), self];
|
|
||||||
delegateQueue.maxConcurrentOperationCount = 1;
|
|
||||||
return delegateQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
_queue = dispatch_queue_create("com.crashlytics.URLSession", 0);
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !__has_feature(objc_arc)
|
|
||||||
- (void)dealloc {
|
|
||||||
[_taskSet release];
|
|
||||||
[_delegate release];
|
|
||||||
[_delegateQueue release];
|
|
||||||
[_configuration release];
|
|
||||||
|
|
||||||
#if !OS_OBJECT_USE_OBJC
|
|
||||||
dispatch_release(_queue);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma mark - Managing the Session
|
|
||||||
|
|
||||||
- (void)invalidateAndCancel {
|
|
||||||
dispatch_sync(_queue, ^{
|
|
||||||
for (FIRCLSURLSessionTask *task in self->_taskSet) {
|
|
||||||
[task cancel];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.delegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)finishTasksAndInvalidate {
|
|
||||||
self.delegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
|
|
||||||
- (void)getTasksWithCompletionHandler:
|
|
||||||
(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler {
|
|
||||||
[[self delegateQueue] addOperationWithBlock:^{
|
|
||||||
// TODO - this is totally wrong, but better than not calling back at all
|
|
||||||
completionHandler(@[], @[], @[]);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)removeTaskFromSet:(FIRCLSURLSessionTask *)task {
|
|
||||||
dispatch_async(_queue, ^{
|
|
||||||
[self->_taskSet removeObject:task];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)configureTask:(FIRCLSURLSessionTask *)task
|
|
||||||
withRequest:(NSURLRequest *)request
|
|
||||||
block:(void (^)(NSMutableURLRequest *mutableRequest))block {
|
|
||||||
NSMutableURLRequest *modifiedRequest = [request mutableCopy];
|
|
||||||
|
|
||||||
dispatch_sync(_queue, ^{
|
|
||||||
[self->_taskSet addObject:task];
|
|
||||||
|
|
||||||
// TODO: this isn't allowed to overwrite existing headers
|
|
||||||
for (NSString *key in [self->_configuration HTTPAdditionalHeaders]) {
|
|
||||||
[modifiedRequest addValue:[[self->_configuration HTTPAdditionalHeaders] objectForKey:key]
|
|
||||||
forHTTPHeaderField:key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (block) {
|
|
||||||
block(modifiedRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
[task setOriginalRequest:modifiedRequest];
|
|
||||||
[task setDelegate:self];
|
|
||||||
|
|
||||||
#if !__has_feature(objc_arc)
|
|
||||||
[modifiedRequest release];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)shouldInvokeDelegateSelector:(SEL)selector forTask:(FIRCLSURLSessionTask *)task {
|
|
||||||
return [task invokesDelegate] && [_delegate respondsToSelector:selector];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Task Creation
|
|
||||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
|
||||||
fromFile:(NSURL *)fileURL {
|
|
||||||
return [self uploadTaskWithRequest:request fromFile:fileURL completionHandler:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request {
|
|
||||||
return [self downloadTaskWithRequest:request completionHandler:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url {
|
|
||||||
return [self downloadTaskWithRequest:[NSURLRequest requestWithURL:url]];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark Async Convenience Methods
|
|
||||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
|
||||||
completionHandler:(nullable void (^)(NSData *data,
|
|
||||||
NSURLResponse *response,
|
|
||||||
NSError *error))completionHandler {
|
|
||||||
FIRCLSURLSessionDataTask *task = [FIRCLSURLSessionDataTask task];
|
|
||||||
|
|
||||||
if (completionHandler) {
|
|
||||||
[task setCompletionHandler:completionHandler];
|
|
||||||
[task setInvokesDelegate:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self configureTask:task withRequest:request block:nil];
|
|
||||||
|
|
||||||
return (NSURLSessionDataTask *)task;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request {
|
|
||||||
return [self dataTaskWithRequest:request completionHandler:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
|
||||||
fromFile:(NSURL *)fileURL
|
|
||||||
completionHandler:
|
|
||||||
(nullable void (^)(NSData *data,
|
|
||||||
NSURLResponse *response,
|
|
||||||
NSError *error))completionHandler {
|
|
||||||
FIRCLSURLSessionUploadTask *task = [FIRCLSURLSessionUploadTask task];
|
|
||||||
|
|
||||||
if (completionHandler) {
|
|
||||||
[task setCompletionHandler:completionHandler];
|
|
||||||
[task setInvokesDelegate:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self configureTask:task
|
|
||||||
withRequest:request
|
|
||||||
block:^(NSMutableURLRequest *mutableRequest) {
|
|
||||||
// you cannot set up both of these, and we'll be using the stream here
|
|
||||||
[mutableRequest setHTTPBody:nil];
|
|
||||||
[mutableRequest setHTTPBodyStream:[NSInputStream inputStreamWithURL:fileURL]];
|
|
||||||
}];
|
|
||||||
|
|
||||||
return (NSURLSessionUploadTask *)task;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
|
|
||||||
completionHandler:
|
|
||||||
(nullable void (^)(NSURL *targetPath,
|
|
||||||
NSURLResponse *response,
|
|
||||||
NSError *error))completionHandler {
|
|
||||||
FIRCLSURLSessionDownloadTask *task = [FIRCLSURLSessionDownloadTask task];
|
|
||||||
|
|
||||||
if (completionHandler) {
|
|
||||||
[task setDownloadCompletionHandler:completionHandler];
|
|
||||||
[task setInvokesDelegate:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self configureTask:task withRequest:request block:nil];
|
|
||||||
|
|
||||||
return (NSURLSessionDownloadTask *)task;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark FIRCLSURLSessionTaskDelegate
|
|
||||||
- (NSURLRequest *)task:(FIRCLSURLSessionTask *)task
|
|
||||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
|
||||||
newRequest:(NSURLRequest *)request {
|
|
||||||
// just accept the proposed redirection
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)task:(FIRCLSURLSessionTask *)task didCompleteWithError:(NSError *)error {
|
|
||||||
if (![self shouldInvokeDelegateSelector:@selector(URLSession:task:didCompleteWithError:)
|
|
||||||
forTask:task]) {
|
|
||||||
[self removeTaskFromSet:task];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_delegateQueue addOperationWithBlock:^{
|
|
||||||
[DELEGATE URLSession:(NSURLSession *)self
|
|
||||||
task:(NSURLSessionTask *)task
|
|
||||||
didCompleteWithError:error];
|
|
||||||
|
|
||||||
// Note that you *cannot* clean up here, because this method could be run asynchronously with
|
|
||||||
// the delegate methods that care about the state of the task
|
|
||||||
[self removeTaskFromSet:task];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark FIRCLSURLSessionDataTask
|
|
||||||
- (void)task:(FIRCLSURLSessionDataTask *)task didReceiveResponse:(NSURLResponse *)response {
|
|
||||||
if (![self shouldInvokeDelegateSelector:@selector
|
|
||||||
(URLSession:dataTask:didReceiveResponse:completionHandler:)
|
|
||||||
forTask:task]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_delegateQueue addOperationWithBlock:^{
|
|
||||||
[DELEGATE URLSession:(NSURLSession *)self
|
|
||||||
dataTask:(NSURLSessionDataTask *)task
|
|
||||||
didReceiveResponse:response
|
|
||||||
completionHandler:^(NSURLSessionResponseDisposition disposition){
|
|
||||||
// nothing to do here
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)task:(FIRCLSURLSessionDataTask *)task didReceiveData:(NSData *)data {
|
|
||||||
if (![self shouldInvokeDelegateSelector:@selector(URLSession:dataTask:didReceiveData:)
|
|
||||||
forTask:task]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_delegateQueue addOperationWithBlock:^{
|
|
||||||
[DELEGATE URLSession:(NSURLSession *)self
|
|
||||||
dataTask:(NSURLSessionDataTask *)task
|
|
||||||
didReceiveData:data];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark FIRCLSURLSessionDownloadDelegate
|
|
||||||
- (void)downloadTask:(FIRCLSURLSessionDownloadTask *)task didFinishDownloadingToURL:(NSURL *)url {
|
|
||||||
if (![self shouldInvokeDelegateSelector:@selector(URLSession:
|
|
||||||
downloadTask:didFinishDownloadingToURL:)
|
|
||||||
forTask:task]) {
|
|
||||||
// We have to be certain that we cleanup only once the delegate no longer cares about the state
|
|
||||||
// of the task being changed. In the case of download, this is either after the delegate method
|
|
||||||
// has been invoked, or here, if the delegate doesn't care.
|
|
||||||
[task cleanup];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[_delegateQueue addOperationWithBlock:^{
|
|
||||||
[DELEGATE URLSession:(NSURLSession *)self
|
|
||||||
downloadTask:(NSURLSessionDownloadTask *)task
|
|
||||||
didFinishDownloadingToURL:url];
|
|
||||||
|
|
||||||
// Cleanup for the download tasks is a little complex. As long as we do it only after
|
|
||||||
// the delegate has been informed of the completed download, we are ok.
|
|
||||||
[task cleanup];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
INJECT_STRIP_SYMBOL(clsurlsession)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright 2019 Google
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#define FIRCLSURLSESSION_REQUIRED (!TARGET_OS_WATCH && !TARGET_OS_TV)
|
|
||||||
|
|
||||||
// These macros generate a function to force a symbol for the containing .o, to work around an issue
|
|
||||||
// where strip will not strip debug information without a symbol to strip.
|
|
||||||
#define CONCAT_EXPANDED(a, b) a##b
|
|
||||||
#define CONCAT(a, b) CONCAT_EXPANDED(a, b)
|
|
||||||
#define DUMMY_FUNCTION_NAME(x) CONCAT(fircls_strip_this_, x)
|
|
||||||
#define INJECT_STRIP_SYMBOL(x) \
|
|
||||||
void DUMMY_FUNCTION_NAME(x)(void) { \
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue