Firebase
This commit is contained in:
parent
228485e3d0
commit
2354e93537
|
@ -5,8 +5,9 @@ apply plugin: "com.android.application"
|
|||
apply plugin: 'kotlin-android'
|
||||
|
||||
if (!isFoss) {
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
apply plugin: 'com.bugsnag.android.gradle'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
}
|
||||
|
||||
import com.android.build.OutputFile
|
||||
|
@ -262,7 +263,7 @@ dependencies {
|
|||
addUnimodulesDependencies()
|
||||
implementation project(':watermelondb')
|
||||
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_analytics')
|
||||
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)
|
||||
if (!isFoss) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ buildscript {
|
|||
|
||||
dependencies {
|
||||
if (isPlay) {
|
||||
classpath 'com.google.gms:google-services:4.2.0'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0'
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.0'
|
||||
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
|
||||
}
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
|
|
|
@ -4,8 +4,8 @@ includeUnimodulesProjects()
|
|||
rootProject.name = 'RocketChatRN'
|
||||
include ':watermelondb'
|
||||
project(':watermelondb').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android')
|
||||
include ':reactnativenotifications'
|
||||
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
|
||||
include ':react-native-notifications'
|
||||
project(':react-native-notifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app')
|
||||
include ':@react-native-community_viewpager'
|
||||
project(':@react-native-community_viewpager').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/viewpager/android')
|
||||
include ':@react-native-firebase_app'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import EJSON from 'ejson';
|
||||
import PushNotification from './push';
|
||||
// import PushNotification from './push';
|
||||
import store from '../../lib/createStore';
|
||||
import { deepLinkingOpen } from '../../actions/deepLinking';
|
||||
import { isFDroidBuild } from '../../constants/environment';
|
||||
|
@ -36,13 +36,14 @@ export const onNotification = (notification) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getDeviceToken = () => PushNotification.getDeviceToken();
|
||||
export const setBadgeCount = count => PushNotification.setBadgeCount(count);
|
||||
export const getDeviceToken = () => {} // PushNotification.getDeviceToken();
|
||||
export const setBadgeCount = count => {} // PushNotification.setBadgeCount(count);
|
||||
export const initializePushNotifications = () => {
|
||||
if (!isFDroidBuild) {
|
||||
setBadgeCount();
|
||||
return PushNotification.configure({
|
||||
onNotification
|
||||
});
|
||||
// return PushNotification.configure({
|
||||
// onNotification
|
||||
// });
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ export const logEvent = (eventName, payload) => {
|
|||
|
||||
export const setCurrentScreen = (currentScreen) => {
|
||||
if (!isFDroidBuild) {
|
||||
analytics().setCurrentScreen(currentScreen);
|
||||
analytics().logScreenView({ screen_name: currentScreen });
|
||||
leaveBreadcrumb(currentScreen, { type: 'navigation' });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,6 +35,8 @@ target 'ShareRocketChatRN' do
|
|||
pod 'RNFBApp', :path => '../node_modules/@react-native-firebase/app'
|
||||
pod 'RNFBAnalytics', :path => '../node_modules/@react-native-firebase/analytics'
|
||||
pod 'RNFBCrashlytics', :path => '../node_modules/@react-native-firebase/crashlytics'
|
||||
$RNFirebaseAnalyticsWithoutAdIdSupport = true
|
||||
|
||||
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage'
|
||||
pod 'RNCMaskedView', :path => '../node_modules/@react-native-community/masked-view'
|
||||
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-jsi (= 0.63.4)
|
||||
- ReactCommon/turbomodule/core (= 0.63.4)
|
||||
- Firebase/Analytics (6.27.1):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (6.27.1):
|
||||
- Firebase/AnalyticsWithoutAdIdSupport (8.1.1):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (= 6.6.2)
|
||||
- Firebase/CoreOnly (6.27.1):
|
||||
- FirebaseCore (= 6.8.1)
|
||||
- Firebase/Crashlytics (6.27.1):
|
||||
- FirebaseAnalytics/WithoutAdIdSupport (~> 8.0.0)
|
||||
- Firebase/CoreOnly (8.1.1):
|
||||
- FirebaseCore (= 8.1.0)
|
||||
- Firebase/Crashlytics (8.1.1):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 4.2.0)
|
||||
- FirebaseAnalytics (6.6.2):
|
||||
- FirebaseCore (~> 6.8)
|
||||
- FirebaseInstallations (~> 1.4)
|
||||
- GoogleAppMeasurement (= 6.6.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (~> 1.30905.0)
|
||||
- FirebaseCore (6.8.1):
|
||||
- FirebaseCoreDiagnostics (~> 1.3)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- FirebaseCoreDiagnostics (1.4.0):
|
||||
- GoogleDataTransportCCTSupport (~> 3.1)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- nanopb (~> 1.30905.0)
|
||||
- FirebaseCrashlytics (4.2.0):
|
||||
- FirebaseCore (~> 6.8)
|
||||
- FirebaseInstallations (~> 1.1)
|
||||
- GoogleDataTransport (~> 6.1)
|
||||
- GoogleDataTransportCCTSupport (~> 3.1)
|
||||
- nanopb (~> 1.30905.0)
|
||||
- FirebaseCrashlytics (~> 8.1.0)
|
||||
- FirebaseAnalytics/Base (8.0.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Network (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAnalytics/WithoutAdIdSupport (8.0.0):
|
||||
- FirebaseAnalytics/Base (= 8.0.0)
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (= 8.0.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Network (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseCore (8.1.0):
|
||||
- FirebaseCoreDiagnostics (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GoogleUtilities/Logger (~> 7.4)
|
||||
- FirebaseCoreDiagnostics (8.1.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)
|
||||
- FirebaseInstallations (1.5.0):
|
||||
- FirebaseCore (~> 6.8)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- FirebaseInstallations (8.1.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GoogleUtilities/UserDefaults (~> 7.4)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- Flipper (0.54.0):
|
||||
- Flipper-Folly (~> 2.2)
|
||||
|
@ -143,34 +149,34 @@ PODS:
|
|||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- GoogleAppMeasurement (6.6.2):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (~> 1.30905.0)
|
||||
- GoogleDataTransport (6.2.1)
|
||||
- GoogleDataTransportCCTSupport (3.2.0):
|
||||
- GoogleDataTransport (~> 6.1)
|
||||
- nanopb (~> 1.30905.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.7.1):
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (8.0.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Network (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleDataTransport (9.0.1):
|
||||
- GoogleUtilities/Environment (~> 7.2)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.4.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (6.7.1):
|
||||
- GoogleUtilities/Environment (7.4.1):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (6.7.1):
|
||||
- GoogleUtilities/Logger (7.4.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (6.7.1):
|
||||
- GoogleUtilities/MethodSwizzler (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (6.7.1):
|
||||
- GoogleUtilities/Network (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (6.7.1)"
|
||||
- GoogleUtilities/Reachability (6.7.1):
|
||||
- "GoogleUtilities/NSData+zlib (7.4.1)"
|
||||
- GoogleUtilities/Reachability (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.7.1):
|
||||
- GoogleUtilities/UserDefaults (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- JitsiMeetSDK (2.10.2)
|
||||
- KeyCommands (2.0.3):
|
||||
|
@ -187,15 +193,15 @@ PODS:
|
|||
- MMKV (1.2.1):
|
||||
- MMKVCore (~> 1.2.1)
|
||||
- MMKVCore (1.2.1)
|
||||
- nanopb (1.30905.0):
|
||||
- nanopb/decode (= 1.30905.0)
|
||||
- nanopb/encode (= 1.30905.0)
|
||||
- nanopb/decode (1.30905.0)
|
||||
- nanopb/encode (1.30905.0)
|
||||
- nanopb (2.30908.0):
|
||||
- nanopb/decode (= 2.30908.0)
|
||||
- nanopb/encode (= 2.30908.0)
|
||||
- nanopb/decode (2.30908.0)
|
||||
- nanopb/encode (2.30908.0)
|
||||
- OpenSSL-Universal (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)
|
||||
- RCTTypeSafety (0.63.4):
|
||||
- FBLazyVector (= 0.63.4)
|
||||
|
@ -382,8 +388,8 @@ PODS:
|
|||
- React
|
||||
- react-native-netinfo (6.0.0):
|
||||
- React-Core
|
||||
- react-native-notifications (2.1.7):
|
||||
- React
|
||||
- react-native-notifications (3.5.0):
|
||||
- React-Core
|
||||
- react-native-orientation-locker (1.3.1):
|
||||
- React-Core
|
||||
- react-native-restart (0.0.22):
|
||||
|
@ -483,17 +489,16 @@ PODS:
|
|||
- React
|
||||
- SDWebImage (~> 5.0)
|
||||
- SDWebImageWebPCoder (~> 0.4.1)
|
||||
- RNFBAnalytics (7.3.1):
|
||||
- Firebase/Analytics (~> 6.27.0)
|
||||
- React
|
||||
- RNFBAnalytics (12.1.0):
|
||||
- Firebase/AnalyticsWithoutAdIdSupport (= 8.1.1)
|
||||
- React-Core
|
||||
- RNFBApp
|
||||
- RNFBApp (8.2.0):
|
||||
- Firebase/CoreOnly (~> 6.27.0)
|
||||
- React
|
||||
- RNFBCrashlytics (8.1.2):
|
||||
- Firebase/Core (~> 6.27.0)
|
||||
- Firebase/Crashlytics (~> 6.27.0)
|
||||
- React
|
||||
- RNFBApp (12.1.0):
|
||||
- Firebase/CoreOnly (= 8.1.1)
|
||||
- React-Core
|
||||
- RNFBCrashlytics (12.1.0):
|
||||
- Firebase/Crashlytics (= 8.1.1)
|
||||
- React-Core
|
||||
- RNFBApp
|
||||
- RNGestureHandler (1.6.1):
|
||||
- React
|
||||
|
@ -678,7 +683,6 @@ SPEC REPOS:
|
|||
- FlipperKit
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
- GoogleDataTransportCCTSupport
|
||||
- GoogleUtilities
|
||||
- libwebp
|
||||
- MMKV
|
||||
|
@ -899,12 +903,12 @@ SPEC CHECKSUMS:
|
|||
EXWebBrowser: d37a5ffdea1b65947352bc001dd9f732463725d4
|
||||
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
||||
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
||||
Firebase: 919186c8e119dd9372a45fd1dd17a8a942bc1892
|
||||
FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4
|
||||
FirebaseCore: 8cd4f8ea22075e0ee582849b1cf79d8816506085
|
||||
FirebaseCoreDiagnostics: 4505e4d4009b1d93f605088ee7d7764d5f0d1c84
|
||||
FirebaseCrashlytics: 7d0fa02ea8842cc4b2ab07b0735edafde1ad77d6
|
||||
FirebaseInstallations: 3c520c951305cbf9ca54eb891ff9e6d1fd384881
|
||||
Firebase: 4bb49ae87756034cef870fa3c4006235eb46f475
|
||||
FirebaseAnalytics: dcb92c7c9ef4fa7ffac276e8f87bd4fc8c97f1b8
|
||||
FirebaseCore: 389c4ce9a7cce4a7e25eb22326b4bee0050557b2
|
||||
FirebaseCoreDiagnostics: 3e249cee3de5c5f9cfd6cc2a19997231286fec11
|
||||
FirebaseCrashlytics: 1b55b3a718f9e20d59d96db46a4652d95a8ba1d2
|
||||
FirebaseInstallations: 7f31798a8198c354eadcb87176d2090b62edc187
|
||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
||||
|
@ -914,18 +918,17 @@ SPEC CHECKSUMS:
|
|||
FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
||||
GoogleAppMeasurement: 8cd1f289d60e629cf16ab03363b9e89c776b9651
|
||||
GoogleDataTransport: 9a8a16f79feffc7f42096743de2a7c4815e84020
|
||||
GoogleDataTransportCCTSupport: 489c1265d2c85b68187a83a911913d190012158d
|
||||
GoogleUtilities: e121a3867449ce16b0e35ddf1797ea7a389ffdf2
|
||||
GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
|
||||
GoogleDataTransport: 04c3e9a480bbcaa2ec3f5d27f1cdeb6a92f20c8d
|
||||
GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
|
||||
JitsiMeetSDK: ef6dd5cfa6d9badf009c7dba1a2c1365bfaae6b0
|
||||
KeyCommands: f66c535f698ed14b3d3a4e58859d79a827ea907e
|
||||
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
|
||||
MMKV: 67253edee25a34edf332f91d73fa94a9e038b971
|
||||
MMKVCore: fe398984acac1fa33f92795d1b5fd0a334c944af
|
||||
nanopb: c43f40fadfe79e8b8db116583945847910cbabc9
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
||||
PromisesObjC: b48e0338dbbac2207e611750777895f7a5811b75
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
||||
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
|
||||
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
|
||||
|
@ -945,7 +948,7 @@ SPEC CHECKSUMS:
|
|||
react-native-jitsi-meet: f2407aca85566e031ee7b222e497ee5ecb6623de
|
||||
react-native-mmkv-storage: 48729fe90e850ef2fdc9d3714b7030c7c51d82b0
|
||||
react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d
|
||||
react-native-notifications: ee8fd739853e72694f3af8b374c8ccb106b7b227
|
||||
react-native-notifications: 89a73cd2cd2648e1734fa10e3507681c9e4f14de
|
||||
react-native-orientation-locker: 998c0744e26624407dac068c04c605b4af7304a2
|
||||
react-native-restart: 733a51ad137f15b0f8dc34c4082e55af7da00979
|
||||
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
|
||||
|
@ -974,9 +977,9 @@ SPEC CHECKSUMS:
|
|||
RNDateTimePicker: 7658208086d86d09e1627b5c34ba0cf237c60140
|
||||
RNDeviceInfo: 8d3a29207835f972bce883723882980143270d55
|
||||
RNFastImage: f40d202ea2367239f71bc7cf11315f4bebab85b4
|
||||
RNFBAnalytics: dae6d7b280ba61c96e1bbdd34aca3154388f025e
|
||||
RNFBApp: 6fd8a7e757135d4168bf033a8812c241af7363a0
|
||||
RNFBCrashlytics: 88de72c2476b5868a892d9523b89b86c527c540e
|
||||
RNFBAnalytics: d8f885de70f3133ca1be101cb5f115e763dbd037
|
||||
RNFBApp: 406bc9586c70ccf20504b4d3b54ac4341c98993f
|
||||
RNFBCrashlytics: 963a2757f6a52e37ae50adab5832162a7d81f98f
|
||||
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
|
||||
RNImageCropPicker: 38865ab4af1b0b2146ad66061196bc0184946855
|
||||
RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b
|
||||
|
@ -1003,6 +1006,6 @@ SPEC CHECKSUMS:
|
|||
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: 0351d0973911a397f1cb4e45f0b0f590b14816e3
|
||||
PODFILE CHECKSUM: 31a91f8b33d73b8680ec7d53c60c76a243f70a20
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
#import <FirebaseAnalytics/FirebaseAnalytics.h>
|
||||
#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>)
|
||||
#import <FirebaseAuth/FirebaseAuth.h>
|
||||
#endif
|
||||
|
@ -36,13 +44,6 @@
|
|||
|
||||
#if __has_include(<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
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
@ -55,118 +56,26 @@ Firebase Dynamic Links works as intended."
|
|||
|
||||
#if __has_include(<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
|
||||
|
||||
#if __has_include(<FirebaseInstanceID/FirebaseInstanceID.h>)
|
||||
#import <FirebaseInstanceID/FirebaseInstanceID.h>
|
||||
#if __has_include(<FirebaseInstallations/FirebaseInstallations.h>)
|
||||
#import <FirebaseInstallations/FirebaseInstallations.h>
|
||||
#endif
|
||||
|
||||
#if __has_include(<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
|
||||
|
||||
#if __has_include(<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
|
||||
|
||||
#if __has_include(<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
|
||||
|
||||
#if __has_include(<FirebaseStorage/FirebaseStorage.h>)
|
||||
#import <FirebaseStorage/FirebaseStorage.h>
|
||||
#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)
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
[![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-appcheck-badge]][gh-actions]
|
||||
[![Actions Status][gh-appdistribution-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-diagnostics-badge]][gh-actions]
|
||||
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
||||
[![Actions Status][gh-database-badge]][gh-actions]
|
||||
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
||||
|
@ -12,9 +16,13 @@
|
|||
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
||||
[![Actions Status][gh-firestore-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-interop-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-storage-badge]][gh-actions]
|
||||
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
||||
|
@ -23,21 +31,23 @@
|
|||
|
||||
# Firebase Apple Open Source Development
|
||||
|
||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
|
||||
FirebasePerformance, 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.
|
||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
|
||||
and FirebaseML.
|
||||
|
||||
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
|
||||
[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
|
||||
|
||||
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. [Swift Package Manager](SwiftPackageManager.md)
|
||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||
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
|
||||
[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
|
||||
to CocoaPods master and available via standard
|
||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
||||
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
|
||||
found at [SwiftPackageManager.md](SwiftPackageManager.md).
|
||||
|
||||
### Installing from GitHub
|
||||
|
||||
These instructions can be used to access the Firebase repo at other branches,
|
||||
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:
|
||||
|
||||
To access FirebaseFirestore via a branch:
|
||||
```
|
||||
```ruby
|
||||
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'
|
||||
```
|
||||
|
||||
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 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||
```
|
||||
|
@ -82,12 +93,8 @@ pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
|||
### Carthage (iOS only)
|
||||
|
||||
Instructions for the experimental Carthage distribution are at
|
||||
[Carthage](Carthage.md).
|
||||
|
||||
### Rome
|
||||
|
||||
Instructions for installing binary frameworks via
|
||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||
[Carthage](Carthage.md). If you have a new Mac with an Apple silicon chip, please see
|
||||
[these instructions](AppleSilicon.md).
|
||||
|
||||
### 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
|
||||
the following software:
|
||||
|
||||
* Xcode 10.3 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* Xcode 12.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)
|
||||
|
||||
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
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
@ -116,7 +132,7 @@ CocoaPods workspaces.
|
|||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
### Development for Catalyst
|
||||
#### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* 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
|
||||
* 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
|
||||
|
||||
See [AddNewPod.md](AddNewPod.md).
|
||||
|
@ -136,40 +164,24 @@ See [HeadersImports.md](HeadersImports.md).
|
|||
### Code Formatting
|
||||
|
||||
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.
|
||||
|
||||
Travis will verify that any code changes are done in a style compliant way. Install
|
||||
`clang-format` and `swiftformat`.
|
||||
These commands will get the right versions:
|
||||
GitHub Actions will verify that any code changes are done in a style compliant
|
||||
way. Install `clang-format` and `mint`:
|
||||
|
||||
```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
|
||||
|
||||
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
|
||||
In order to run the sample apps and integration tests, you'll need valid
|
||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
||||
In order to run the sample apps and integration tests, you'll need a valid
|
||||
`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
|
||||
`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
|
||||
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`)
|
||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
||||
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
|
||||
|
||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
||||
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.
|
||||
### Coverage Report Generation
|
||||
|
||||
See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md).
|
||||
|
||||
## Specific Component Instructions
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
account, and enable that App ID for push notifications.
|
||||
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]**.
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
### tvOS, macOS, watchOS and Catalyst
|
||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
||||
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 tvOS, macOS, watchOS and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
|
||||
[Independent Watch App Sample](Example/watchOSSample).
|
||||
For tvOS, see the [Sample](Example/tvOSSample).
|
||||
For watchOS, currently only Messaging, Storage and Crashlytics (and their dependencies) have limited
|
||||
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
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and
|
||||
this repository is actively developed primarily for iOS. While we can catch basic unit test issues
|
||||
with GitHub Actions, there may be some changes where the SDK no longer works as expected on macOS,
|
||||
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
|
||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
|
||||
During app setup in the console, you may get to a step that mentions something like "Checking if the
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
|
@ -273,6 +287,10 @@ to Build Settings.
|
|||
* FirebaseFirestore requires signing the
|
||||
[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
|
||||
|
||||
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-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-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-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-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
|
||||
|
@ -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-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-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-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-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-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
|
||||
|
|
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_click</li>
|
||||
/// <li>ad_exposure</li>
|
||||
/// <li>ad_impression</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>screen_view</li>
|
||||
/// <li>session_start</li>
|
||||
/// <li>session_start_with_rollout</li>
|
||||
/// <li>user_engagement</li>
|
||||
/// </ul>
|
||||
///
|
||||
|
@ -49,7 +61,7 @@ NS_SWIFT_NAME(Analytics)
|
|||
/// 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.
|
||||
/// 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
|
||||
|
@ -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.
|
||||
+ (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
|
||||
/// persisted across app sessions. By default it is enabled.
|
||||
///
|
||||
|
@ -125,13 +110,33 @@ NS_SWIFT_NAME(Analytics)
|
|||
/// session terminates.
|
||||
+ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval;
|
||||
|
||||
/// The unique ID for this instance of the application.
|
||||
+ (NSString *)appInstanceID;
|
||||
/// 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
|
|
@ -52,6 +52,21 @@ static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart)
|
|||
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
|
||||
|
@ -246,6 +261,15 @@ static NSString *const kFIREventPurchaseRefund NS_SWIFT_NAME(AnalyticsEventPurch
|
|||
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:
|
|
@ -22,6 +22,17 @@
|
|||
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 = @{
|
||||
|
@ -32,6 +43,36 @@ static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParamet
|
|||
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 = @{
|
||||
|
@ -368,6 +409,26 @@ static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQua
|
|||
/// </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 = @{
|
|
@ -1,4 +1,5 @@
|
|||
#import "FIRAnalytics+AppDelegate.h"
|
||||
#import "FIRAnalytics+Consent.h"
|
||||
#import "FIRAnalytics.h"
|
||||
#import "FIREventNames.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 {
|
||||
umbrella header "FirebaseAnalytics.h"
|
||||
export *
|
||||
module * { export * }
|
||||
link "sqlite3"
|
||||
link "z"
|
||||
link framework "CoreData"
|
||||
umbrella header "FirebaseAnalytics.h"
|
||||
export *
|
||||
module * { export * }
|
||||
link framework "CoreTelephony"
|
||||
link framework "Foundation"
|
||||
link framework "Security"
|
||||
link framework "StoreKit"
|
||||
link framework "SystemConfiguration"
|
||||
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>
|
||||
#endif
|
||||
|
||||
#import "FirebaseCore/Sources/Public/FIRApp.h"
|
||||
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h"
|
||||
|
||||
#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h"
|
||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||
#import "FirebaseCore/Sources/FIRComponentContainerInternal.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/FIRCoreDiagnosticsConnector.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
|
||||
|
@ -71,8 +73,6 @@ NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat =
|
|||
NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey =
|
||||
@"FirebaseDataCollectionDefaultEnabled";
|
||||
|
||||
NSString *const kFIRAppDiagnosticsNotification = @"FIRAppDiagnosticsNotification";
|
||||
|
||||
NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType";
|
||||
NSString *const kFIRAppDiagnosticsErrorKey = @"Error";
|
||||
NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp";
|
||||
|
@ -90,6 +90,14 @@ NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey =
|
|||
NSString *const 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.
|
||||
*/
|
||||
|
@ -116,8 +124,6 @@ static NSMutableArray<Class<FIRLibrary>> *sRegisteredAsConfigurable;
|
|||
|
||||
static NSMutableDictionary *sAllApps;
|
||||
static FIRApp *sDefaultApp;
|
||||
static NSMutableDictionary *sLibraryVersions;
|
||||
static dispatch_once_t sFirebaseUserAgentOnceToken;
|
||||
|
||||
+ (void)configure {
|
||||
FIROptions *options = [FIROptions defaultOptions];
|
||||
|
@ -277,9 +283,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
sDefaultApp = nil;
|
||||
[sAllApps removeAllObjects];
|
||||
sAllApps = nil;
|
||||
[sLibraryVersions removeAllObjects];
|
||||
sLibraryVersions = nil;
|
||||
sFirebaseUserAgentOnceToken = 0;
|
||||
[[self userAgent] reset];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,9 +349,6 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
return NO;
|
||||
}
|
||||
|
||||
[self logCoreTelemetryIfEnabled];
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
// Initialize the Analytics once there is a valid options under default app. Analytics should
|
||||
// always initialize first by itself before the other SDKs.
|
||||
if ([self.name isEqualToString:kFIRDefaultAppName]) {
|
||||
|
@ -368,7 +369,6 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[self subscribeForAppDidBecomeActiveNotifications];
|
||||
|
||||
|
@ -479,20 +479,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
NSLocalizedRecoverySuggestionErrorKey :
|
||||
@"Check formatting and location of GoogleService-Info.plist."
|
||||
};
|
||||
return [NSError errorWithDomain:kFirebaseCoreErrorDomain
|
||||
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];
|
||||
return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-100 userInfo:errorDict];
|
||||
}
|
||||
|
||||
+ (NSError *)errorForInvalidAppID {
|
||||
|
@ -502,9 +489,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
@"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the "
|
||||
@"customized options."
|
||||
};
|
||||
return [NSError errorWithDomain:kFirebaseCoreErrorDomain
|
||||
code:FIRErrorCodeInvalidAppID
|
||||
userInfo:errorDict];
|
||||
return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-101 userInfo:errorDict];
|
||||
}
|
||||
|
||||
+ (BOOL)isDefaultAppConfigured {
|
||||
|
@ -520,12 +505,7 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
// add the name/version pair to the dictionary.
|
||||
if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound &&
|
||||
[version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) {
|
||||
@synchronized(self) {
|
||||
if (!sLibraryVersions) {
|
||||
sLibraryVersions = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
sLibraryVersions[name] = version;
|
||||
}
|
||||
[[self userAgent] setValue:version forComponent:name];
|
||||
} else {
|
||||
FIRLogError(kFIRLoggerCore, @"I-COR000027",
|
||||
@"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
|
||||
withName:(nonnull NSString *)name
|
||||
withVersion:(nonnull NSString *)version {
|
||||
|
@ -561,73 +546,18 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
[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 {
|
||||
@synchronized(self) {
|
||||
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;
|
||||
return [[self userAgent] firebaseUserAgent];
|
||||
}
|
||||
|
||||
- (void)checkExpectedBundleID {
|
||||
|
@ -897,17 +827,6 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
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
|
||||
|
||||
- (void)subscribeForAppDidBecomeActiveNotifications {
|
||||
|
@ -931,7 +850,9 @@ static dispatch_once_t sFirebaseUserAgentOnceToken;
|
|||
|
||||
- (void)logCoreTelemetryIfEnabled {
|
||||
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 "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||
|
||||
@class FIRApp;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRConfiguration.h"
|
||||
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h"
|
||||
|
||||
@class FIRAnalyticsConfiguration;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#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/Private/FIRAppInternal.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#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/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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,18 +18,18 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This class represents a future data object, determined at instantiation time. */
|
||||
@interface GDTCORDataFuture : NSObject <NSSecureCoding>
|
||||
@interface FIRFirebaseUserAgent : NSObject
|
||||
|
||||
/** If not nil, this data future was instantiated with this file URL. */
|
||||
@property(nullable, readonly, nonatomic) NSURL *fileURL;
|
||||
/** Returns the firebase user agent which consists of environment part and the components added via
|
||||
* `setValue:forComponent` method. */
|
||||
- (NSString *)firebaseUserAgent;
|
||||
|
||||
/** Initializes an instance with the given the fileURL.
|
||||
*
|
||||
* @param fileURL The fileURL containing the data to return in -data.
|
||||
* @return An instance of this class.
|
||||
*/
|
||||
- (instancetype)initWithFileURL:(NSURL *)fileURL;
|
||||
/** Sets value associated with the specified component. If value is `nil` then the component is
|
||||
* removed. */
|
||||
- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName;
|
||||
|
||||
/** Resets manually added components. */
|
||||
- (void)reset;
|
||||
|
||||
@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.
|
||||
|
||||
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
||||
#import <GoogleUtilities/GULHeartbeatDateStorable.h>
|
||||
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||
#import <GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h>
|
||||
#import <GoogleUtilities/GULLogger.h>
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
|
||||
const static long secondsInDay = 86400;
|
||||
@implementation FIRHeartbeatInfo : NSObject
|
||||
|
@ -25,9 +28,17 @@ const static long secondsInDay = 86400;
|
|||
*/
|
||||
+ (BOOL)updateIfNeededHeartbeatDateForTag:(NSString *)heartbeatTag {
|
||||
@synchronized(self) {
|
||||
NSString *const kHeartbeatStorageFile = @"HEARTBEAT_INFO_STORAGE";
|
||||
GULHeartbeatDateStorage *dataStorage =
|
||||
[[GULHeartbeatDateStorage alloc] initWithFileName:kHeartbeatStorageFile];
|
||||
NSString *const kHeartbeatStorageName = @"HEARTBEAT_INFO_STORAGE";
|
||||
id<GULHeartbeatDateStorable> dataStorage;
|
||||
#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 *currentDate = [NSDate date];
|
||||
if (heartbeatTime != nil) {
|
||||
|
|
|
@ -16,20 +16,15 @@
|
|||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.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]";
|
||||
|
||||
// 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 kFIRLoggerAuth = @"[Firebase/Auth]";
|
||||
FIRLoggerService kFIRLoggerCrash = @"[Firebase/Crash]";
|
||||
FIRLoggerService kFIRLoggerMLKit = @"[Firebase/MLKit]";
|
||||
FIRLoggerService kFIRLoggerPerf = @"[Firebase/Performance]";
|
||||
FIRLoggerService kFIRLoggerRemoteConfig = @"[Firebase/RemoteConfig]";
|
||||
|
||||
/// Arguments passed on launch.
|
||||
|
@ -58,10 +53,10 @@ static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$";
|
|||
static NSRegularExpression *sMessageCodeRegex;
|
||||
#endif
|
||||
|
||||
void FIRLoggerInitializeASL() {
|
||||
void FIRLoggerInitializeASL(void) {
|
||||
dispatch_once(&sFIRLoggerOnceToken, ^{
|
||||
// Register Firebase Version with GULLogger.
|
||||
GULLoggerRegisterVersion(FIRVersionString);
|
||||
GULLoggerRegisterVersion(FIRFirebaseVersion());
|
||||
|
||||
// Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in.
|
||||
NSArray *arguments = [NSProcessInfo processInfo].arguments;
|
||||
|
@ -101,7 +96,7 @@ void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) {
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void FIRResetLogger() {
|
||||
void FIRResetLogger(void) {
|
||||
extern void GULResetLogger(void);
|
||||
sFIRLoggerOnceToken = 0;
|
||||
[sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey];
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
// limitations under the License.
|
||||
|
||||
#import "FirebaseCore/Sources/FIRBundleUtil.h"
|
||||
#import "FirebaseCore/Sources/FIRVersion.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLogger.h"
|
||||
#import "FirebaseCore/Sources/Private/FIROptionsInternal.h"
|
||||
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||
|
||||
// Keys for the strings in the plist file.
|
||||
NSString *const kFIRAPIKey = @"API_KEY";
|
||||
|
@ -90,40 +90,40 @@ NSString *const kFIRExceptionBadModification =
|
|||
|
||||
static FIROptions *sDefaultOptions = nil;
|
||||
static NSDictionary *sDefaultOptionsDictionary = nil;
|
||||
static dispatch_once_t sDefaultOptionsOnceToken;
|
||||
static dispatch_once_t sDefaultOptionsDictionaryOnceToken;
|
||||
|
||||
#pragma mark - Public only for internal class methods
|
||||
|
||||
+ (FIROptions *)defaultOptions {
|
||||
if (sDefaultOptions != nil) {
|
||||
return sDefaultOptions;
|
||||
}
|
||||
dispatch_once(&sDefaultOptionsOnceToken, ^{
|
||||
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;
|
||||
}
|
||||
|
||||
#pragma mark - Private class methods
|
||||
|
||||
+ (NSDictionary *)defaultOptionsDictionary {
|
||||
if (sDefaultOptionsDictionary != nil) {
|
||||
return sDefaultOptionsDictionary;
|
||||
}
|
||||
NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName];
|
||||
if (plistFilePath == nil) {
|
||||
return nil;
|
||||
}
|
||||
sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
||||
if (sDefaultOptionsDictionary == nil) {
|
||||
FIRLogError(kFIRLoggerCore, @"I-COR000011",
|
||||
@"The configuration file is not a dictionary: "
|
||||
@"'%@.%@'.",
|
||||
kServiceInfoFileName, kServiceInfoFileType);
|
||||
}
|
||||
dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{
|
||||
NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName];
|
||||
if (plistFilePath == nil) {
|
||||
return;
|
||||
}
|
||||
sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
||||
if (sDefaultOptionsDictionary == nil) {
|
||||
FIRLogError(kFIRLoggerCore, @"I-COR000011",
|
||||
@"The configuration file is not a dictionary: "
|
||||
@"'%@.%@'.",
|
||||
kServiceInfoFileName, kServiceInfoFileType);
|
||||
}
|
||||
});
|
||||
|
||||
return sDefaultOptionsDictionary;
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,8 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
+ (void)resetDefaultOptions {
|
||||
sDefaultOptions = nil;
|
||||
sDefaultOptionsDictionary = nil;
|
||||
sDefaultOptionsOnceToken = 0;
|
||||
sDefaultOptionsDictionaryOnceToken = 0;
|
||||
}
|
||||
|
||||
#pragma mark - Private instance methods
|
||||
|
@ -158,9 +160,9 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
FIROptions *newOptions = [[[self class] allocWithZone:zone] init];
|
||||
FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone]
|
||||
initInternalWithOptionsDictionary:self.optionsDictionary];
|
||||
if (newOptions) {
|
||||
newOptions.optionsDictionary = self.optionsDictionary;
|
||||
newOptions.deepLinkURLScheme = self.deepLinkURLScheme;
|
||||
newOptions.appGroupID = self.appGroupID;
|
||||
newOptions.editingLocked = self.isEditingLocked;
|
||||
|
@ -171,6 +173,12 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
|
||||
#pragma mark - Public instance methods
|
||||
|
||||
- (instancetype)init {
|
||||
// Unavailable.
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithContentsOfFile:(NSString *)plistPath {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
|
@ -277,7 +285,7 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
|
|||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// 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:@"."];
|
||||
NSString *major = [components objectAtIndex:0];
|
||||
NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]];
|
||||
|
|
|
@ -14,14 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h"
|
||||
|
||||
#ifndef Firebase_VERSION
|
||||
#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation"
|
||||
#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
|
||||
// preprocessor does not try to parse the version as a floating
|
||||
// point number. See
|
||||
|
@ -29,5 +27,6 @@
|
|||
#define STR(x) STR_EXPAND(x)
|
||||
#define STR_EXPAND(x) #x
|
||||
|
||||
const char *const FIRVersionString = (const char *const)STR(Firebase_VERSION);
|
||||
const char *const FIRCoreVersionString = (const char *const)STR(FIRCore_VERSION);
|
||||
NSString* FIRFirebaseVersion(void) {
|
||||
return @STR(Firebase_VERSION);
|
||||
}
|
||||
|
|
|
@ -14,19 +14,7 @@
|
|||
* 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>
|
||||
#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;
|
||||
@protocol FIRLibrary;
|
||||
|
@ -51,6 +39,10 @@ extern NSString *const kFIRAppDeleteNotification;
|
|||
extern NSString *const kFIRAppIsDefaultAppKey;
|
||||
extern NSString *const kFIRAppNameKey;
|
||||
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.
|
||||
|
@ -63,11 +55,6 @@ extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat;
|
|||
*/
|
||||
extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey;
|
||||
|
||||
/**
|
||||
* A notification fired containing diagnostic information when SDK errors occur.
|
||||
*/
|
||||
extern NSString *const kFIRAppDiagnosticsNotification;
|
||||
|
||||
/** @var FIRAuthStateDidChangeInternalNotification
|
||||
@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
|
||||
|
@ -110,14 +97,6 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
|||
*/
|
||||
@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.
|
||||
*/
|
||||
|
@ -132,9 +111,19 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
|||
*/
|
||||
+ (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
|
||||
* 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 name Name of the library.
|
||||
|
@ -149,15 +138,6 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
|
|||
*/
|
||||
+ (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.
|
||||
*/
|
||||
|
|
|
@ -15,15 +15,6 @@
|
|||
*/
|
||||
#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
|
||||
|
||||
/// 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.
|
||||
* @return Heartbeat code indicating whether or not an sdk/global heartbeat
|
||||
* needs to be sent
|
||||
|
|
|
@ -19,14 +19,8 @@
|
|||
|
||||
#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 FIRComponent;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
|
|
@ -16,12 +16,7 @@
|
|||
|
||||
#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>
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -30,14 +25,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
typedef NSString *const FIRLoggerService;
|
||||
|
||||
extern FIRLoggerService kFIRLoggerABTesting;
|
||||
extern FIRLoggerService kFIRLoggerAdMob;
|
||||
extern FIRLoggerService kFIRLoggerAnalytics;
|
||||
extern FIRLoggerService kFIRLoggerAuth;
|
||||
extern FIRLoggerService kFIRLoggerCrash;
|
||||
extern FIRLoggerService kFIRLoggerCore;
|
||||
extern FIRLoggerService kFIRLoggerMLKit;
|
||||
extern FIRLoggerService kFIRLoggerPerf;
|
||||
extern FIRLoggerService kFIRLoggerRemoteConfig;
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,12 +14,7 @@
|
|||
* 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>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
|
|
|
@ -15,15 +15,12 @@
|
|||
// 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.
|
||||
|
||||
#if SWIFT_PACKAGE
|
||||
@import FirebaseCore;
|
||||
#else
|
||||
#import <FirebaseCore/FirebaseCore.h>
|
||||
#endif
|
||||
|
||||
#import "FirebaseCore/Sources/Private/FIRAppInternal.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponent.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentContainer.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRComponentType.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRDependency.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h"
|
||||
#import "FirebaseCore/Sources/Private/FIRLibrary.h"
|
||||
|
|
|
@ -106,7 +106,7 @@ NS_SWIFT_NAME(FirebaseOptions)
|
|||
* FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
|
||||
* 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
|
||||
|
@ -115,9 +115,12 @@ NS_SWIFT_NAME(FirebaseOptions)
|
|||
// clang-format off
|
||||
- (instancetype)initWithGoogleAppID:(NSString *)googleAppID
|
||||
GCMSenderID:(NSString *)GCMSenderID
|
||||
NS_SWIFT_NAME(init(googleAppID:gcmSenderID:));
|
||||
NS_SWIFT_NAME(init(googleAppID:gcmSenderID:)) NS_DESIGNATED_INITIALIZER;
|
||||
// clang-format on
|
||||
|
||||
/** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +16,10 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "FIRErrorCode.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const kFirebaseErrorDomain;
|
||||
extern NSString *const kFirebaseConfigErrorDomain;
|
||||
extern NSString *const kFirebaseCoreErrorDomain;
|
||||
extern NSString *const kFirebasePerfErrorDomain;
|
||||
/** Returns the current version of Firebase. */
|
||||
NS_SWIFT_NAME(FirebaseVersion())
|
||||
NSString* FIRFirebaseVersion(void);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -18,3 +18,4 @@
|
|||
#import "FIRConfiguration.h"
|
||||
#import "FIRLoggerLevel.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)
|
||||
|
||||
[![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-cocoapods-integration-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-database-badge]][gh-actions]
|
||||
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
||||
|
@ -12,9 +16,13 @@
|
|||
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
||||
[![Actions Status][gh-firestore-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-interop-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-storage-badge]][gh-actions]
|
||||
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
||||
|
@ -23,21 +31,23 @@
|
|||
|
||||
# Firebase Apple Open Source Development
|
||||
|
||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
|
||||
FirebasePerformance, 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.
|
||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
|
||||
and FirebaseML.
|
||||
|
||||
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
|
||||
[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
|
||||
|
||||
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. [Swift Package Manager](SwiftPackageManager.md)
|
||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||
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
|
||||
[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
|
||||
to CocoaPods master and available via standard
|
||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
||||
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
|
||||
found at [SwiftPackageManager.md](SwiftPackageManager.md).
|
||||
|
||||
### Installing from GitHub
|
||||
|
||||
These instructions can be used to access the Firebase repo at other branches,
|
||||
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:
|
||||
|
||||
To access FirebaseFirestore via a branch:
|
||||
```
|
||||
```ruby
|
||||
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'
|
||||
```
|
||||
|
||||
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 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||
```
|
||||
|
@ -82,12 +93,8 @@ pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
|||
### Carthage (iOS only)
|
||||
|
||||
Instructions for the experimental Carthage distribution are at
|
||||
[Carthage](Carthage.md).
|
||||
|
||||
### Rome
|
||||
|
||||
Instructions for installing binary frameworks via
|
||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||
[Carthage](Carthage.md). If you have a new Mac with an Apple silicon chip, please see
|
||||
[these instructions](AppleSilicon.md).
|
||||
|
||||
### 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
|
||||
the following software:
|
||||
|
||||
* Xcode 10.3 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* Xcode 12.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)
|
||||
|
||||
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
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
@ -116,7 +132,7 @@ CocoaPods workspaces.
|
|||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
### Development for Catalyst
|
||||
#### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* 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
|
||||
* 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
|
||||
|
||||
See [AddNewPod.md](AddNewPod.md).
|
||||
|
@ -136,40 +164,24 @@ See [HeadersImports.md](HeadersImports.md).
|
|||
### Code Formatting
|
||||
|
||||
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.
|
||||
|
||||
Travis will verify that any code changes are done in a style compliant way. Install
|
||||
`clang-format` and `swiftformat`.
|
||||
These commands will get the right versions:
|
||||
GitHub Actions will verify that any code changes are done in a style compliant
|
||||
way. Install `clang-format` and `mint`:
|
||||
|
||||
```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
|
||||
|
||||
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
|
||||
In order to run the sample apps and integration tests, you'll need valid
|
||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
||||
In order to run the sample apps and integration tests, you'll need a valid
|
||||
`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
|
||||
`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
|
||||
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`)
|
||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
||||
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
|
||||
|
||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
||||
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.
|
||||
### Coverage Report Generation
|
||||
|
||||
See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md).
|
||||
|
||||
## Specific Component Instructions
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
account, and enable that App ID for push notifications.
|
||||
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]**.
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
### tvOS, macOS, watchOS and Catalyst
|
||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
||||
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 tvOS, macOS, watchOS and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
|
||||
[Independent Watch App Sample](Example/watchOSSample).
|
||||
For tvOS, see the [Sample](Example/tvOSSample).
|
||||
For watchOS, currently only Messaging, Storage and Crashlytics (and their dependencies) have limited
|
||||
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
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and
|
||||
this repository is actively developed primarily for iOS. While we can catch basic unit test issues
|
||||
with GitHub Actions, there may be some changes where the SDK no longer works as expected on macOS,
|
||||
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
|
||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
|
||||
During app setup in the console, you may get to a step that mentions something like "Checking if the
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
|
@ -273,6 +287,10 @@ to Build Settings.
|
|||
* FirebaseFirestore requires signing the
|
||||
[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
|
||||
|
||||
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-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-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-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-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
|
||||
|
@ -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-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-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-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-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-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
|
||||
|
|
|
@ -17,10 +17,7 @@
|
|||
#import <objc/runtime.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
|
||||
#import <GoogleDataTransport/GDTCOREvent.h>
|
||||
#import <GoogleDataTransport/GDTCORTargets.h>
|
||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
||||
#import <GoogleDataTransport/GoogleDataTransport.h>
|
||||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
|
||||
|
@ -33,7 +30,7 @@
|
|||
#import <nanopb/pb_decode.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. */
|
||||
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
|
||||
|
@ -44,7 +41,9 @@ static BOOL kUsingZipFile = YES;
|
|||
static BOOL kUsingZipFile = NO;
|
||||
#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
|
||||
#elif FIREBASE_BUILD_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
|
||||
#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 kFIRServiceAdMob = @"AdMob";
|
||||
|
@ -200,24 +192,6 @@ NS_ASSUME_NONNULL_END
|
|||
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
|
||||
|
||||
/** 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 :
|
||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE),
|
||||
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 :
|
||||
@(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER),
|
||||
kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS),
|
||||
|
@ -379,7 +341,7 @@ void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfigu
|
|||
config->icore_version = FIREncodeString(libraryVersionID);
|
||||
}
|
||||
|
||||
NSString *deviceModel = [FIRCoreDiagnostics deviceModel];
|
||||
NSString *deviceModel = [GULAppEnvironmentUtil deviceModel];
|
||||
if (deviceModel.length) {
|
||||
config->device_model = FIREncodeString(deviceModel);
|
||||
}
|
||||
|
@ -422,40 +384,6 @@ void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfigu
|
|||
[sdkServiceInstalledArray
|
||||
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
|
||||
if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) {
|
||||
[sdkServiceInstalledArray
|
||||
|
@ -526,29 +454,6 @@ void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfigu
|
|||
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.
|
||||
*
|
||||
* @param config The proto to populate.
|
||||
|
@ -604,7 +509,6 @@ void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfigura
|
|||
FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects);
|
||||
FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects);
|
||||
FIRPopulateProtoWithInstalledServices(&icore_config);
|
||||
FIRPopulateProtoWithNumberOfLinkedFrameworks(&icore_config);
|
||||
FIRPopulateProtoWithInfoPlistValues(&icore_config);
|
||||
[self setHeartbeatFlagIfNeededToConfig:&icore_config];
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.3.9.5 */
|
||||
/* Generated by nanopb-0.3.9.7 */
|
||||
|
||||
#include "firebasecore.nanopb.h"
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
/* 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
|
||||
#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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,6 +14,5 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
FOUNDATION_EXPORT const char *const FIRInstallationsVersionStr;
|
||||
// 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.
|
|
@ -3,8 +3,12 @@
|
|||
[![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-appcheck-badge]][gh-actions]
|
||||
[![Actions Status][gh-appdistribution-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-diagnostics-badge]][gh-actions]
|
||||
[![Actions Status][gh-crashlytics-badge]][gh-actions]
|
||||
[![Actions Status][gh-database-badge]][gh-actions]
|
||||
[![Actions Status][gh-datatransport-badge]][gh-actions]
|
||||
|
@ -12,9 +16,13 @@
|
|||
[![Actions Status][gh-firebasepod-badge]][gh-actions]
|
||||
[![Actions Status][gh-firestore-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-interop-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-storage-badge]][gh-actions]
|
||||
[![Actions Status][gh-symbolcollision-badge]][gh-actions]
|
||||
|
@ -23,21 +31,23 @@
|
|||
|
||||
# Firebase Apple Open Source Development
|
||||
|
||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics,
|
||||
FirebasePerformance, 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.
|
||||
This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics
|
||||
and FirebaseML.
|
||||
|
||||
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
|
||||
[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
|
||||
|
||||
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. [Swift Package Manager](SwiftPackageManager.md)
|
||||
1. [Installing from the GitHub repo](README.md#installing-from-github)
|
||||
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
|
||||
[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
|
||||
to CocoaPods master and available via standard
|
||||
[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod).
|
||||
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
|
||||
found at [SwiftPackageManager.md](SwiftPackageManager.md).
|
||||
|
||||
### Installing from GitHub
|
||||
|
||||
These instructions can be used to access the Firebase repo at other branches,
|
||||
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:
|
||||
|
||||
To access FirebaseFirestore via a branch:
|
||||
```
|
||||
```ruby
|
||||
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'
|
||||
```
|
||||
|
||||
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 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
||||
```
|
||||
|
@ -82,12 +93,8 @@ pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
|
|||
### Carthage (iOS only)
|
||||
|
||||
Instructions for the experimental Carthage distribution are at
|
||||
[Carthage](Carthage.md).
|
||||
|
||||
### Rome
|
||||
|
||||
Instructions for installing binary frameworks via
|
||||
[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md).
|
||||
[Carthage](Carthage.md). If you have a new Mac with an Apple silicon chip, please see
|
||||
[these instructions](AppleSilicon.md).
|
||||
|
||||
### 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
|
||||
the following software:
|
||||
|
||||
* Xcode 10.3 (or later)
|
||||
* CocoaPods 1.7.2 (or later)
|
||||
* Xcode 12.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)
|
||||
|
||||
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
|
||||
`pod repo update` before the `pod gen` command.
|
||||
|
@ -116,7 +132,7 @@ CocoaPods workspaces.
|
|||
Firestore has a self contained Xcode project. See
|
||||
[Firestore/README.md](Firestore/README.md).
|
||||
|
||||
### Development for Catalyst
|
||||
#### Development for Catalyst
|
||||
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
|
||||
* Check the Mac box in the App-iOS Build Settings
|
||||
* 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
|
||||
* 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
|
||||
|
||||
See [AddNewPod.md](AddNewPod.md).
|
||||
|
@ -136,40 +164,24 @@ See [HeadersImports.md](HeadersImports.md).
|
|||
### Code Formatting
|
||||
|
||||
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.
|
||||
|
||||
Travis will verify that any code changes are done in a style compliant way. Install
|
||||
`clang-format` and `swiftformat`.
|
||||
These commands will get the right versions:
|
||||
GitHub Actions will verify that any code changes are done in a style compliant
|
||||
way. Install `clang-format` and `mint`:
|
||||
|
||||
```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
|
||||
|
||||
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
|
||||
In order to run the sample apps and integration tests, you'll need valid
|
||||
`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist
|
||||
In order to run the sample apps and integration tests, you'll need a valid
|
||||
`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
|
||||
`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
|
||||
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`)
|
||||
4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file
|
||||
(e.g. in [Example/Database/App/](Example/Database/App/));
|
||||
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
|
||||
|
||||
Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require
|
||||
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.
|
||||
### Coverage Report Generation
|
||||
|
||||
See [scripts/code_coverage_report/README.md](scripts/code_coverage_report/README.md).
|
||||
|
||||
## Specific Component Instructions
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
account, and enable that App ID for push notifications.
|
||||
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]**.
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
### tvOS, macOS, watchOS and Catalyst
|
||||
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on
|
||||
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 tvOS, macOS, watchOS and Catalyst.
|
||||
|
||||
For tvOS, checkout the [Sample](Example/tvOSSample).
|
||||
For watchOS, currently only Messaging and Storage (and their dependencies) have limited support. Checkout the
|
||||
[Independent Watch App Sample](Example/watchOSSample).
|
||||
For tvOS, see the [Sample](Example/tvOSSample).
|
||||
For watchOS, currently only Messaging, Storage and Crashlytics (and their dependencies) have limited
|
||||
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
|
||||
repository is actively developed primarily for iOS. While we can catch basic unit test issues with
|
||||
Travis, there may be some changes where the SDK no longer works as expected on macOS, tvOS or watchOS. If you
|
||||
encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
|
||||
Keep in mind that macOS, tvOS, watchOS and Catalyst are not officially supported by Firebase, and
|
||||
this repository is actively developed primarily for iOS. While we can catch basic unit test issues
|
||||
with GitHub Actions, there may be some changes where the SDK no longer works as expected on macOS,
|
||||
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
|
||||
has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/watchOS/Catalyst.
|
||||
During app setup in the console, you may get to a step that mentions something like "Checking if the
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability`
|
||||
|
@ -273,6 +287,10 @@ to Build Settings.
|
|||
* FirebaseFirestore requires signing the
|
||||
[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
|
||||
|
||||
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-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-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-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-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
|
||||
|
@ -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-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-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-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-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-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
|
||||
|
|
|
@ -47,6 +47,11 @@ NSString* FIRCLSApplicationGetSDKBundleID(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
|
||||
*/
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "FIRCLSApplication.h"
|
||||
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||
|
||||
#import "FIRCLSHost.h"
|
||||
#import "FIRCLSUtility.h"
|
||||
#import "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
|
||||
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
||||
|
||||
#if CLS_TARGET_OS_OSX
|
||||
#import <AppKit/AppKit.h>
|
||||
|
@ -44,9 +46,29 @@ NSString* FIRCLSApplicationGetPlatform(void) {
|
|||
return @"mac";
|
||||
#elif TARGET_OS_TV
|
||||
return @"tvos";
|
||||
#elif TARGET_OS_WATCH
|
||||
return @"ios"; // TODO: temporarily use iOS until Firebase can add watchos to the backend
|
||||
#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
|
||||
NSString* FIRCLSApplicationGetBundleVersion(void) {
|
||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FIRCLSFeatures.h"
|
||||
#include "FIRCLSFile.h"
|
||||
#include "FIRCLSMachO.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSBinaryImage.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h"
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <mach-o/dyld.h>
|
||||
|
@ -21,13 +21,13 @@
|
|||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "FIRCLSByteUtility.h"
|
||||
#include "FIRCLSFeatures.h"
|
||||
#include "FIRCLSFile.h"
|
||||
#include "FIRCLSGlobals.h"
|
||||
#include "FIRCLSHost.h"
|
||||
#include "FIRCLSMachO.h"
|
||||
#include "FIRCLSUtility.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
#include "Crashlytics/Shared/FIRCLSByteUtility.h"
|
||||
#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
|
@ -363,20 +363,17 @@ static void FIRCLSBinaryImageChanged(bool added,
|
|||
const struct mach_header* mh,
|
||||
intptr_t vmaddr_slide) {
|
||||
// FIRCLSSDKLog("Binary image %s %p\n", added ? "loaded" : "unloaded", mh);
|
||||
|
||||
FIRCLSBinaryImageDetails imageDetails;
|
||||
|
||||
memset(&imageDetails, 0, sizeof(FIRCLSBinaryImageDetails));
|
||||
|
||||
imageDetails.slice = FIRCLSMachOSliceWithHeader((void*)mh);
|
||||
imageDetails.vmaddr_slide = vmaddr_slide;
|
||||
FIRCLSBinaryImageFillInImageDetails(&imageDetails);
|
||||
|
||||
// this is an atomic operation
|
||||
FIRCLSBinaryImageStoreNode(added, imageDetails);
|
||||
|
||||
// this isn't, so do it on a serial queue
|
||||
// Do these time-consuming operations on a background queue
|
||||
dispatch_async(FIRCLSGetBinaryImageQueue(), ^{
|
||||
// this is an atomic operation
|
||||
FIRCLSBinaryImageStoreNode(added, imageDetails);
|
||||
FIRCLSBinaryImageRecordSlice(added, imageDetails);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "FIRCLSAllocate.h"
|
||||
#include "FIRCLSBinaryImage.h"
|
||||
#include "FIRCLSException.h"
|
||||
#include "FIRCLSFeatures.h"
|
||||
#include "FIRCLSHost.h"
|
||||
#include "FIRCLSInternalLogging.h"
|
||||
#include "FIRCLSMachException.h"
|
||||
#include "FIRCLSSignal.h"
|
||||
#include "FIRCLSUserLogging.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||
#include "Crashlytics/Crashlytics/Handlers/FIRCLSException.h"
|
||||
#include "Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h"
|
||||
#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h"
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -57,7 +57,9 @@ typedef struct {
|
|||
FIRCLSBinaryImageReadOnlyContext binaryimage;
|
||||
FIRCLSExceptionReadOnlyContext exception;
|
||||
FIRCLSHostReadOnlyContext host;
|
||||
#if CLS_SIGNAL_SUPPORTED
|
||||
FIRCLSSignalReadContext signal;
|
||||
#endif
|
||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||
FIRCLSMachExceptionReadContext machException;
|
||||
#endif
|
||||
|
@ -84,7 +86,6 @@ typedef struct {
|
|||
const char* rootPath;
|
||||
const char* previouslyCrashedFileRootPath;
|
||||
const char* sessionId;
|
||||
const char* installId;
|
||||
const char* betaToken;
|
||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||
exception_mask_t machExceptionMask;
|
||||
|
@ -100,14 +101,8 @@ typedef struct {
|
|||
#ifdef __OBJC__
|
||||
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
||||
FIRCLSSettings* settings,
|
||||
FIRCLSInstallIdentifierModel* installIDModel,
|
||||
FIRCLSFileManager* fileManager);
|
||||
|
||||
// Re-writes the metadata file on the current thread
|
||||
void FIRCLSContextUpdateMetadata(FIRCLSInternalReport* report,
|
||||
FIRCLSSettings* settings,
|
||||
FIRCLSInstallIdentifierModel* installIDModel,
|
||||
FIRCLSFileManager* fileManager);
|
||||
#endif
|
||||
|
||||
void FIRCLSContextBaseInit(void);
|
||||
|
|
|
@ -12,23 +12,25 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSContext.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#import "FIRCLSFileManager.h"
|
||||
#import "FIRCLSInstallIdentifierModel.h"
|
||||
#import "FIRCLSInternalReport.h"
|
||||
#import "FIRCLSSettings.h"
|
||||
#import "Crashlytics/Shared/FIRCLSConstants.h"
|
||||
|
||||
#include "FIRCLSApplication.h"
|
||||
#include "FIRCLSCrashedMarkerFile.h"
|
||||
#include "FIRCLSDefines.h"
|
||||
#include "FIRCLSFeatures.h"
|
||||
#include "FIRCLSGlobals.h"
|
||||
#include "FIRCLSProcess.h"
|
||||
#include "FIRCLSUtility.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
|
||||
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSApplication.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
|
||||
// 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,
|
||||
FIRCLSSettings* settings,
|
||||
FIRCLSInstallIdentifierModel* installIDModel,
|
||||
FIRCLSFileManager* fileManager) {
|
||||
// Because we need to start the crash reporter right away,
|
||||
// it starts up either with default settings, or cached settings
|
||||
|
@ -62,7 +63,6 @@ FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
|||
memset(&initData, 0, sizeof(FIRCLSContextInitData));
|
||||
|
||||
initData.customBundleId = nil;
|
||||
initData.installId = [installIDModel.installID UTF8String];
|
||||
initData.sessionId = [[report identifier] UTF8String];
|
||||
initData.rootPath = [[report path] UTF8String];
|
||||
initData.previouslyCrashedFileRootPath = [[fileManager rootPath] UTF8String];
|
||||
|
@ -72,6 +72,7 @@ FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
|||
initData.maxErrorLogSize = [settings errorLogBufferSize];
|
||||
initData.maxLogSize = [settings logBufferSize];
|
||||
initData.maxKeyValues = [settings maxCustomKeys];
|
||||
initData.betaToken = "";
|
||||
|
||||
// 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,
|
||||
|
@ -98,10 +99,8 @@ FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
|
|||
|
||||
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
||||
FIRCLSSettings* settings,
|
||||
FIRCLSInstallIdentifierModel* installIDModel,
|
||||
FIRCLSFileManager* fileManager) {
|
||||
FIRCLSContextInitData initDataObj =
|
||||
FIRCLSContextBuildInitData(report, settings, installIDModel, fileManager);
|
||||
FIRCLSContextInitData initDataObj = FIRCLSContextBuildInitData(report, settings, fileManager);
|
||||
FIRCLSContextInitData* initData = &initDataObj;
|
||||
|
||||
if (!initData) {
|
||||
|
@ -194,13 +193,18 @@ bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
|||
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 CLS_SIGNAL_SUPPORTED
|
||||
dispatch_group_async(group, queue, ^{
|
||||
_firclsContext.readonly->signal.path =
|
||||
FIRCLSContextAppendToRoot(rootPath, FIRCLSReportSignalFile);
|
||||
|
||||
FIRCLSSignalInitialize(&_firclsContext.readonly->signal);
|
||||
});
|
||||
#endif
|
||||
|
||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||
dispatch_group_async(group, queue, ^{
|
||||
|
@ -255,24 +259,6 @@ bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
|
|||
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) {
|
||||
NSString* sdkBundleID = FIRCLSApplicationGetSDKBundleID();
|
||||
|
||||
|
@ -397,13 +383,15 @@ static bool FIRCLSContextRecordIdentity(FIRCLSFile* file, const FIRCLSContextIni
|
|||
|
||||
FIRCLSFileWriteHashStart(file);
|
||||
|
||||
FIRCLSFileWriteHashEntryString(file, "generator", CLS_SDK_GENERATOR_NAME);
|
||||
FIRCLSFileWriteHashEntryString(file, "display_version", CLS_SDK_DISPLAY_VERSION);
|
||||
FIRCLSFileWriteHashEntryString(file, "build_version", CLS_SDK_DISPLAY_VERSION);
|
||||
FIRCLSFileWriteHashEntryString(file, "generator", FIRCLSSDKGeneratorName().UTF8String);
|
||||
FIRCLSFileWriteHashEntryString(file, "display_version", FIRCLSSDKVersion().UTF8String);
|
||||
FIRCLSFileWriteHashEntryString(file, "build_version", FIRCLSSDKVersion().UTF8String);
|
||||
FIRCLSFileWriteHashEntryUint64(file, "started_at", time(NULL));
|
||||
|
||||
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);
|
||||
FIRCLSFileWriteHashEntryBoolean(file, "absolute_log_timestamps", true);
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSCrashedMarkerFile.h"
|
||||
#include "FIRCLSFile.h"
|
||||
#include "FIRCLSUtility.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
|
||||
const char *FIRCLSCrashedMarkerFileName = "previously-crashed";
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSContext.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <mach/vm_types.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "FIRCLSFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
|
||||
typedef struct {
|
||||
const char* documentDirectoryPath;
|
||||
|
@ -34,4 +34,6 @@ bool FIRCLSHostRecord(FIRCLSFile* file);
|
|||
|
||||
void FIRCLSHostWriteDiskUsage(FIRCLSFile* file);
|
||||
|
||||
bool FIRCLSHostIsRosettaTranslated(void);
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -12,18 +12,18 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSHost.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#import "FIRCLSApplication.h"
|
||||
#include "FIRCLSDefines.h"
|
||||
#import "FIRCLSFABHost.h"
|
||||
#include "FIRCLSFile.h"
|
||||
#include "FIRCLSGlobals.h"
|
||||
#include "FIRCLSUtility.h"
|
||||
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
#import "Crashlytics/Shared/FIRCLSFABHost.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
|
@ -32,9 +32,10 @@
|
|||
#endif
|
||||
|
||||
#define CLS_HOST_SYSCTL_BUFFER_SIZE (128)
|
||||
#define CLS_MAX_ARM64_NATIVE_PAGE_SIZE (1024 * 16)
|
||||
|
||||
#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
|
||||
// return 4K, which is correct for all platforms except arm64, currently
|
||||
#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
|
||||
// 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;
|
||||
size = sizeof(pageSize);
|
||||
if (sysctlbyname("hw.pagesize", &pageSize, &size, NULL, 0) != 0) {
|
||||
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 (size != sizeof(pageSize)) {
|
||||
return CLS_MAX_NATIVE_PAGE_SIZE;
|
||||
return maxNativePageSize;
|
||||
}
|
||||
|
||||
// put in some guards to make sure our size is reasonable
|
||||
if (pageSize > CLS_MAX_NATIVE_PAGE_SIZE) {
|
||||
return CLS_MAX_NATIVE_PAGE_SIZE;
|
||||
if (pageSize > maxNativePageSize) {
|
||||
return maxNativePageSize;
|
||||
}
|
||||
|
||||
if (pageSize < CLS_MIN_NATIVE_PAGE_SIZE) {
|
||||
|
@ -93,6 +104,29 @@ vm_size_t FIRCLSHostGetPageSize(void) {
|
|||
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(
|
||||
FIRCLSFile* file, const char* key, const char* sysctlKey, void* buffer, size_t bufferSize) {
|
||||
if (sysctlbyname(sysctlKey, buffer, &bufferSize, NULL, 0) != 0) {
|
||||
|
@ -124,6 +158,8 @@ static void FIRCLSHostWriteOSVersionInfo(FIRCLSFile* file) {
|
|||
FIRCLSFileWriteHashEntryString(file, "os_display_version",
|
||||
[FIRCLSHostOSDisplayVersion() UTF8String]);
|
||||
FIRCLSFileWriteHashEntryString(file, "platform", [FIRCLSApplicationGetPlatform() UTF8String]);
|
||||
FIRCLSFileWriteHashEntryString(file, "firebase_platform",
|
||||
[FIRCLSApplicationGetFirebasePlatform() UTF8String]);
|
||||
}
|
||||
|
||||
bool FIRCLSHostRecord(FIRCLSFile* file) {
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSProcess.h"
|
||||
#include "FIRCLSDefines.h"
|
||||
#include "FIRCLSFeatures.h"
|
||||
#include "FIRCLSGlobals.h"
|
||||
#include "FIRCLSProfiling.h"
|
||||
#include "FIRCLSThreadState.h"
|
||||
#include "FIRCLSUnwind.h"
|
||||
#include "FIRCLSUtility.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSProfiling.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h"
|
||||
#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <objc/message.h>
|
||||
|
@ -57,10 +57,6 @@ bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uap
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FIRCLSProcessDestroy(FIRCLSProcess *process) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
|
||||
bool FIRCLSProcessDebuggerAttached(void) {
|
||||
int junk;
|
||||
|
@ -167,7 +163,7 @@ static bool FIRCLSProcessGetThreadState(FIRCLSProcess *process,
|
|||
thread_t thread,
|
||||
FIRCLSThreadContext *context) {
|
||||
if (!FIRCLSIsValidPointer(context)) {
|
||||
FIRCLSSDKLogError("invalid context supplied");
|
||||
FIRCLSSDKLogError("Invalid context supplied\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -216,9 +212,14 @@ static bool FIRCLSProcessGetThreadState(FIRCLSProcess *process,
|
|||
#if !TARGET_OS_WATCH
|
||||
// try to get the value by querying the thread state
|
||||
mach_msg_type_number_t stateCount = FIRCLSThreadStateCount;
|
||||
if (thread_get_state(thread, FIRCLSThreadState, (thread_state_t)(&(context->__ss)),
|
||||
&stateCount) != KERN_SUCCESS) {
|
||||
FIRCLSSDKLogError("failed to get thread state\n");
|
||||
|
||||
// For unknown reasons, thread_get_state returns this value on Rosetta,
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -254,7 +255,7 @@ static const char *FIRCLSProcessGetThreadDispatchQueueName(FIRCLSProcess *proces
|
|||
infoCount = THREAD_IDENTIFIER_INFO_COUNT;
|
||||
if (thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&info, &infoCount) !=
|
||||
KERN_SUCCESS) {
|
||||
FIRCLSSDKLog("unable to get thread info\n");
|
||||
FIRCLSSDKLog("Unable to get thread info\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -390,12 +391,12 @@ static bool FIRCLSProcessRecordThread(FIRCLSProcess *process, thread_t thread, F
|
|||
FIRCLSThreadContext context;
|
||||
|
||||
if (!FIRCLSProcessGetThreadState(process, thread, &context)) {
|
||||
FIRCLSSDKLogError("unable to get thread state");
|
||||
FIRCLSSDKLogError("Unable to get thread state\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FIRCLSUnwindInit(&unwindContext, context)) {
|
||||
FIRCLSSDKLog("unable to init unwind context\n");
|
||||
FIRCLSSDKLog("Unable to init unwind context\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -485,6 +486,11 @@ bool FIRCLSProcessRecordAllThreads(FIRCLSProcess *process, FIRCLSFile *file) {
|
|||
|
||||
FIRCLSSDKLogInfo("recording thread %d data\n", i);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -493,7 +499,7 @@ bool FIRCLSProcessRecordAllThreads(FIRCLSProcess *process, FIRCLSFile *file) {
|
|||
|
||||
FIRCLSFileWriteSectionEnd(file);
|
||||
|
||||
FIRCLSSDKLogInfo("completed recording all thread data\n");
|
||||
FIRCLSSDKLogInfo("Completed recording all thread data\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -541,6 +547,11 @@ void FIRCLSProcessRecordDispatchQueueNames(FIRCLSProcess *process, FIRCLSFile *f
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -795,6 +806,12 @@ static void FIRCLSProcessRecordCrashInfo(FIRCLSFile *file) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <mach/mach.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "FIRCLSFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
|
||||
typedef struct {
|
||||
// task info
|
||||
|
@ -32,7 +32,6 @@ typedef struct {
|
|||
} FIRCLSProcess;
|
||||
|
||||
bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uapVoid);
|
||||
bool FIRCLSProcessDestroy(FIRCLSProcess *process);
|
||||
bool FIRCLSProcessDebuggerAttached(void);
|
||||
|
||||
bool FIRCLSProcessSuspendAllOtherThreads(FIRCLSProcess *process);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "FIRCLSFile.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -75,6 +75,7 @@ void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext* roContext,
|
|||
|
||||
#ifdef __OBJC__
|
||||
void FIRCLSUserLoggingRecordUserKeyValue(NSString* key, id value);
|
||||
void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary* keysAndValues);
|
||||
void FIRCLSUserLoggingRecordInternalKeyValue(NSString* key, id value);
|
||||
void FIRCLSUserLoggingWriteInternalKeyValue(NSString* key, NSString* value);
|
||||
|
||||
|
@ -89,6 +90,10 @@ void FIRCLSUserLoggingRecordKeyValue(NSString* key,
|
|||
FIRCLSUserLoggingKVStorage* storage,
|
||||
uint32_t* counter);
|
||||
|
||||
void FIRCLSUserLoggingRecordKeysAndValues(NSDictionary* keysAndValues,
|
||||
FIRCLSUserLoggingKVStorage* storage,
|
||||
uint32_t* counter);
|
||||
|
||||
void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage* storage,
|
||||
const char** activePath,
|
||||
void (^openedFileBlock)(FIRCLSFile* file));
|
||||
|
@ -96,6 +101,11 @@ void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage* storage,
|
|||
NSArray* FIRCLSUserLoggingStoredKeyValues(const char* path);
|
||||
|
||||
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
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "FIRCLSUserLogging.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "FIRCLSGlobals.h"
|
||||
#include "FIRCLSUtility.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.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 FIRCLSFirstRunloopTurnTimeKey = @"com.crashlytics.first-run-loop-time";
|
||||
|
@ -33,17 +33,21 @@ NSString *const FIRCLSDevelopmentPlatformNameKey = @"com.crashlytics.development
|
|||
NSString *const FIRCLSDevelopmentPlatformVersionKey =
|
||||
@"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;
|
||||
|
||||
#pragma mark - Prototypes
|
||||
static void FIRCLSUserLoggingWriteKeyValue(NSString *key,
|
||||
NSString *value,
|
||||
FIRCLSUserLoggingKVStorage *storage,
|
||||
uint32_t *counter);
|
||||
static void FIRCLSUserLoggingWriteKeysAndValues(NSDictionary *keysAndValues,
|
||||
FIRCLSUserLoggingKVStorage *storage,
|
||||
uint32_t *counter);
|
||||
static void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage,
|
||||
const char **activePath,
|
||||
off_t fileSize);
|
||||
void FIRCLSLogInternal(NSString *message);
|
||||
void FIRCLSLogInternal(FIRCLSUserLoggingABStorage *storage,
|
||||
const char **activePath,
|
||||
NSString *message);
|
||||
|
||||
#pragma mark - Setup
|
||||
void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext *roContext,
|
||||
|
@ -68,8 +72,10 @@ void FIRCLSUserLoggingRecordInternalKeyValue(NSString *key, id value) {
|
|||
|
||||
void FIRCLSUserLoggingWriteInternalKeyValue(NSString *key, NSString *value) {
|
||||
// Unsynchronized - must be run on the correct queue
|
||||
FIRCLSUserLoggingWriteKeyValue(key, value, &_firclsContext.readonly->logging.internalKVStorage,
|
||||
&_firclsContext.writable->logging.internalKVCount);
|
||||
NSDictionary *keysAndValues = key ? @{key : value ?: [NSNull null]} : nil;
|
||||
FIRCLSUserLoggingWriteKeysAndValues(keysAndValues,
|
||||
&_firclsContext.readonly->logging.internalKVStorage,
|
||||
&_firclsContext.writable->logging.internalKVCount);
|
||||
}
|
||||
|
||||
void FIRCLSUserLoggingRecordUserKeyValue(NSString *key, id value) {
|
||||
|
@ -77,6 +83,12 @@ void FIRCLSUserLoggingRecordUserKeyValue(NSString *key, id value) {
|
|||
&_firclsContext.writable->logging.userKVCount);
|
||||
}
|
||||
|
||||
void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary *keysAndValues) {
|
||||
FIRCLSUserLoggingRecordKeysAndValues(keysAndValues,
|
||||
&_firclsContext.readonly->logging.userKVStorage,
|
||||
&_firclsContext.writable->logging.userKVCount);
|
||||
}
|
||||
|
||||
static id FIRCLSUserLoggingGetComponent(NSDictionary *entry,
|
||||
NSString *componentName,
|
||||
bool decodeHex) {
|
||||
|
@ -140,6 +152,30 @@ NSDictionary *FIRCLSUserLoggingGetCompactedKVEntries(FIRCLSUserLoggingKVStorage
|
|||
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) {
|
||||
if (!FIRCLSIsValidPointer(storage)) {
|
||||
FIRCLSSDKLogError("Error: storage invalid\n");
|
||||
|
@ -167,24 +203,14 @@ void FIRCLSUserLoggingCompactKVEntries(FIRCLSUserLoggingKVStorage *storage) {
|
|||
// but it's very uncommon to go down this path.
|
||||
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 dictionaryWithValuesForKeys:[keys subarrayWithRange:NSMakeRange(0, maxCount)]];
|
||||
}
|
||||
|
||||
for (NSString *key in finalKVs) {
|
||||
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);
|
||||
}
|
||||
|
||||
FIRCLSUserLoggingWriteKVEntriesToFile(finalKVs, false, &file);
|
||||
FIRCLSFileClose(&file);
|
||||
|
||||
if (unlink(storage->incrementalPath) != 0) {
|
||||
|
@ -202,33 +228,59 @@ void FIRCLSUserLoggingRecordKeyValue(NSString *key,
|
|||
return;
|
||||
}
|
||||
|
||||
// ensure that any invalid pointer is actually set to nil
|
||||
if (!FIRCLSIsValidPointer(value) && value != nil) {
|
||||
FIRCLSSDKLogWarn("Bad value pointer being clamped to nil\n");
|
||||
value = nil;
|
||||
}
|
||||
NSDictionary *keysAndValues = @{key : (value ?: [NSNull null])};
|
||||
FIRCLSUserLoggingRecordKeysAndValues(keysAndValues, storage, counter);
|
||||
}
|
||||
|
||||
void FIRCLSUserLoggingRecordKeysAndValues(NSDictionary *keysAndValues,
|
||||
FIRCLSUserLoggingKVStorage *storage,
|
||||
uint32_t *counter) {
|
||||
if (!FIRCLSContextIsInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([value respondsToSelector:@selector(description)]) {
|
||||
value = [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
|
||||
value = nil;
|
||||
if (keysAndValues.count == 0) {
|
||||
FIRCLSSDKLogWarn("User provided empty key/value dictionary\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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(), ^{
|
||||
FIRCLSUserLoggingWriteKeyValue(key, value, storage, counter);
|
||||
FIRCLSUserLoggingWriteKeysAndValues(sanitizedKeysAndValues, storage, counter);
|
||||
});
|
||||
}
|
||||
|
||||
static void FIRCLSUserLoggingWriteKeyValue(NSString *key,
|
||||
NSString *value,
|
||||
FIRCLSUserLoggingKVStorage *storage,
|
||||
uint32_t *counter) {
|
||||
static void FIRCLSUserLoggingWriteKeysAndValues(NSDictionary *keysAndValues,
|
||||
FIRCLSUserLoggingKVStorage *storage,
|
||||
uint32_t *counter) {
|
||||
FIRCLSFile file;
|
||||
|
||||
if (!FIRCLSIsValidPointer(storage) || !FIRCLSIsValidPointer(counter)) {
|
||||
|
@ -241,16 +293,10 @@ static void FIRCLSUserLoggingWriteKeyValue(NSString *key,
|
|||
return;
|
||||
}
|
||||
|
||||
FIRCLSFileWriteSectionStart(&file, "kv");
|
||||
FIRCLSFileWriteHashStart(&file);
|
||||
FIRCLSFileWriteHashEntryHexEncodedString(&file, "key", [key UTF8String]);
|
||||
FIRCLSFileWriteHashEntryHexEncodedString(&file, "value", [value UTF8String]);
|
||||
FIRCLSFileWriteHashEnd(&file);
|
||||
FIRCLSFileWriteSectionEnd(&file);
|
||||
|
||||
FIRCLSUserLoggingWriteKVEntriesToFile(keysAndValues, true, &file);
|
||||
FIRCLSFileClose(&file);
|
||||
|
||||
*counter += 1;
|
||||
*counter += keysAndValues.count;
|
||||
if (*counter >= storage->maxIncrementalCount) {
|
||||
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
||||
FIRCLSUserLoggingCompactKVEntries(storage);
|
||||
|
@ -356,7 +402,26 @@ void FIRCLSLog(NSString *format, ...) {
|
|||
NSString *msg = [[NSString alloc] initWithFormat:format arguments: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
|
||||
|
@ -426,7 +491,9 @@ void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage,
|
|||
[[NSFileManager defaultManager] removeItemAtPath:pathString error:nil];
|
||||
}
|
||||
|
||||
*activePath = otherPath;
|
||||
@synchronized(FIRCLSSynchronizedPathKey) {
|
||||
*activePath = otherPath;
|
||||
}
|
||||
}
|
||||
|
||||
void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage *storage,
|
||||
|
@ -436,8 +503,10 @@ void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage *storage,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!*activePath) {
|
||||
return;
|
||||
@synchronized(FIRCLSSynchronizedPathKey) {
|
||||
if (!*activePath) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (storage->restrictBySize) {
|
||||
|
@ -484,7 +553,9 @@ void FIRCLSLogInternalWrite(FIRCLSFile *file, NSString *message, uint64_t time)
|
|||
FIRCLSFileWriteSectionEnd(file);
|
||||
}
|
||||
|
||||
void FIRCLSLogInternal(NSString *message) {
|
||||
void FIRCLSLogInternal(FIRCLSUserLoggingABStorage *storage,
|
||||
const char **activePath,
|
||||
NSString *message) {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
@ -498,7 +569,7 @@ void FIRCLSLogInternal(NSString *message) {
|
|||
struct timeval te;
|
||||
|
||||
NSUInteger messageLength = [message length];
|
||||
int maxLogSize = _firclsContext.readonly->logging.logStorage.maxSize;
|
||||
int maxLogSize = storage->maxSize;
|
||||
|
||||
if (messageLength > maxLogSize) {
|
||||
FIRCLSWarningLog(
|
||||
|
@ -515,9 +586,7 @@ void FIRCLSLogInternal(NSString *message) {
|
|||
|
||||
const uint64_t time = te.tv_sec * 1000LL + te.tv_usec / 1000;
|
||||
|
||||
FIRCLSUserLoggingWriteAndCheckABFiles(&_firclsContext.readonly->logging.logStorage,
|
||||
&_firclsContext.writable->logging.activeUserLogPath,
|
||||
^(FIRCLSFile *file) {
|
||||
FIRCLSLogInternalWrite(file, message, time);
|
||||
});
|
||||
FIRCLSUserLoggingWriteAndCheckABFiles(storage, activePath, ^(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");
|
||||
// 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
|
||||
// limitations under the License.
|
||||
|
||||
#import "FIRCLSURLSessionAvailability.h"
|
||||
|
||||
#if FIRCLSURLSESSION_REQUIRED
|
||||
|
||||
#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
|
||||
|
||||
#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>
|
||||
|
||||
#include "FIRCLSApplicationIdentifierModel.h"
|
||||
#include "FIRCLSProfiling.h"
|
||||
#include "FIRCrashlytics.h"
|
||||
#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h"
|
||||
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSProfiling.h"
|
||||
|
||||
@class FBLPromise<T>;
|
||||
@class FIRCLSExistingReportManager;
|
||||
@class FIRCLSAnalyticsManager;
|
||||
@class FIRCLSManagerData;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FIRCLSDataCollectionArbiter;
|
||||
@class FIRCLSFileManager;
|
||||
@class FIRCLSInternalReport;
|
||||
@class FIRCLSSettings;
|
||||
@class GDTCORTransport;
|
||||
@class FIRInstallations;
|
||||
@protocol FIRAnalyticsInterop;
|
||||
|
||||
@interface FIRCLSReportManager : NSObject
|
||||
|
||||
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager
|
||||
installations:(FIRInstallations *)installations
|
||||
analytics:(nullable id<FIRAnalyticsInterop>)analytics
|
||||
googleAppID:(NSString *)googleAppID
|
||||
dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter
|
||||
googleTransport:(GDTCORTransport *)googleTransport
|
||||
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel
|
||||
settings:(FIRCLSSettings *)settings NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
|
||||
existingReportManager:(FIRCLSExistingReportManager *)existingReportManager
|
||||
analyticsManager:(FIRCLSAnalyticsManager *)analyticsManager
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
- (FBLPromise<NSNumber *> *)startWithProfilingMark:(FIRCLSProfileMark)mark;
|
||||
|
||||
- (FBLPromise<NSNumber *> *)checkForUnsentReports;
|
||||
- (FBLPromise<FIRCrashlyticsReport *> *)checkForUnsentReports;
|
||||
- (FBLPromise *)sendUnsentReports;
|
||||
- (FBLPromise *)deleteUnsentReports;
|
||||
|
||||
|
|
|
@ -38,37 +38,34 @@
|
|||
#import "FBLPromises.h"
|
||||
#endif
|
||||
|
||||
#import "FIRCLSApplication.h"
|
||||
#import "FIRCLSDataCollectionArbiter.h"
|
||||
#import "FIRCLSDataCollectionToken.h"
|
||||
#import "FIRCLSDefines.h"
|
||||
#import "FIRCLSFeatures.h"
|
||||
#import "FIRCLSFileManager.h"
|
||||
#import "FIRCLSInternalReport.h"
|
||||
#import "FIRCLSLogger.h"
|
||||
#import "FIRCLSNetworkClient.h"
|
||||
#import "FIRCLSPackageReportOperation.h"
|
||||
#import "FIRCLSProcessReportOperation.h"
|
||||
#import "FIRCLSReportUploader.h"
|
||||
#import "FIRCLSSettings.h"
|
||||
#import "FIRCLSSymbolResolver.h"
|
||||
#import "FIRCLSUserLogging.h"
|
||||
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||
#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h"
|
||||
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
|
||||
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.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 "FIRCLSUtility.h"
|
||||
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
|
||||
#import "FIRCLSConstants.h"
|
||||
#import "FIRCLSExecutionIdentifierModel.h"
|
||||
#import "FIRCLSInstallIdentifierModel.h"
|
||||
#import "FIRCLSSettingsOnboardingManager.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||
#import "Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h"
|
||||
#import "Crashlytics/Shared/FIRCLSConstants.h"
|
||||
|
||||
#import "FIRCLSReportManager_Private.h"
|
||||
|
||||
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
||||
#import "Interop/Analytics/Public/FIRAnalyticsInteropListener.h"
|
||||
|
||||
#include "FIRAEvent+Internal.h"
|
||||
#include "FIRCLSFCRAnalytics.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
|
@ -76,29 +73,6 @@
|
|||
#import <AppKit/AppKit.h>
|
||||
#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.
|
||||
*/
|
||||
|
@ -119,24 +93,15 @@ typedef NSNumber FIRCLSWrappedReportAction;
|
|||
}
|
||||
@end
|
||||
|
||||
/**
|
||||
* This is a helper to make code using NSNumber for bools more readable.
|
||||
*/
|
||||
typedef NSNumber FIRCLSWrappedBool;
|
||||
|
||||
@interface FIRCLSReportManager () <FIRCLSNetworkClientDelegate,
|
||||
FIRCLSReportUploaderDelegate,
|
||||
FIRCLSReportUploaderDataSource> {
|
||||
@interface FIRCLSReportManager () {
|
||||
FIRCLSFileManager *_fileManager;
|
||||
FIRCLSNetworkClient *_networkClient;
|
||||
FIRCLSReportUploader *_uploader;
|
||||
dispatch_queue_t _dispatchQueue;
|
||||
NSOperationQueue *_operationQueue;
|
||||
id<FIRAnalyticsInterop> _analytics;
|
||||
|
||||
// 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.
|
||||
FBLPromise<FIRCLSWrappedBool *> *_unsentReportsAvailable;
|
||||
FBLPromise<FIRCrashlyticsReport *> *_unsentReportsAvailable;
|
||||
|
||||
// A promise that will be resolved when the user has provided an action that they want to perform
|
||||
// for all the unsent reports.
|
||||
|
@ -156,63 +121,49 @@ typedef NSNumber FIRCLSWrappedBool;
|
|||
}
|
||||
|
||||
@property(nonatomic, readonly) NSString *googleAppID;
|
||||
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
||||
|
||||
@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;
|
||||
|
||||
// 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;
|
||||
@property(nonatomic, strong) FIRCLSAnalyticsManager *analyticsManager;
|
||||
@property(nonatomic, strong) FIRCLSExistingReportManager *existingReportManager;
|
||||
|
||||
// Runs the operations that fetch settings and call onboarding endpoints
|
||||
@property(nonatomic, strong) FIRCLSSettingsOnboardingManager *settingsAndOnboardingManager;
|
||||
|
||||
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
||||
// Internal Managers
|
||||
@property(nonatomic, strong) FIRCLSSettingsManager *settingsManager;
|
||||
@property(nonatomic, strong) FIRCLSNotificationManager *notificationManager;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FIRCLSReportManager
|
||||
|
||||
// Used only for internal data collection E2E testing
|
||||
static void (^reportSentCallback)(void);
|
||||
|
||||
- (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 {
|
||||
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
|
||||
existingReportManager:(FIRCLSExistingReportManager *)existingReportManager
|
||||
analyticsManager:(FIRCLSAnalyticsManager *)analyticsManager {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_fileManager = fileManager;
|
||||
_analytics = analytics;
|
||||
_googleAppID = [googleAppID copy];
|
||||
_dataArbiter = dataArbiter;
|
||||
_fileManager = managerData.fileManager;
|
||||
_analytics = managerData.analytics;
|
||||
_googleAppID = [managerData.googleAppID copy];
|
||||
_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;
|
||||
|
||||
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];
|
||||
_existingReportManager = existingReportManager;
|
||||
_analyticsManager = analyticsManager;
|
||||
|
||||
_unsentReportsAvailable = [FBLPromise pendingPromise];
|
||||
_reportActionProvided = [FBLPromise pendingPromise];
|
||||
|
@ -220,42 +171,19 @@ static void (^reportSentCallback)(void);
|
|||
|
||||
_checkForUnsentReportsCalled = NO;
|
||||
|
||||
_installIDModel = [[FIRCLSInstallIdentifierModel alloc] initWithInstallations:installations];
|
||||
_executionIDModel = [[FIRCLSExecutionIdentifierModel alloc] init];
|
||||
_settingsManager = [[FIRCLSSettingsManager alloc] initWithAppIDModel:self.appIDModel
|
||||
installIDModel:self.installIDModel
|
||||
settings:self.settings
|
||||
fileManager:self.fileManager
|
||||
googleAppID:self.googleAppID];
|
||||
|
||||
_settings = settings;
|
||||
_appIDModel = appIDModel;
|
||||
_notificationManager = [[FIRCLSNotificationManager alloc] init];
|
||||
|
||||
_settingsAndOnboardingManager =
|
||||
[[FIRCLSSettingsOnboardingManager alloc] initWithAppIDModel:appIDModel
|
||||
installIDModel:self.installIDModel
|
||||
settings:self.settings
|
||||
fileManager:self.fileManager
|
||||
googleAppID:self.googleAppID];
|
||||
_launchMarker = [[FIRCLSLaunchMarkerModel alloc] initWithFileManager:_fileManager];
|
||||
|
||||
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
|
||||
// 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.
|
||||
|
@ -264,8 +192,8 @@ static void (^reportSentCallback)(void);
|
|||
// 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.
|
||||
- (FBLPromise<FIRCLSWrappedReportAction *> *)waitForReportAction {
|
||||
FIRCLSDebugLog(@"[Crashlytics:Crash] Notifying that unsent reports are available.");
|
||||
[_unsentReportsAvailable fulfill:@YES];
|
||||
FIRCrashlyticsReport *unsentReport = self.existingReportManager.newestUnsentReport;
|
||||
[_unsentReportsAvailable fulfill:unsentReport];
|
||||
|
||||
// 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.
|
||||
|
@ -275,16 +203,16 @@ static void (^reportSentCallback)(void);
|
|||
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.
|
||||
return [FBLPromise race:@[ collectionEnabled, _reportActionProvided ]];
|
||||
}
|
||||
|
||||
- (FBLPromise<FIRCLSWrappedBool *> *)checkForUnsentReports {
|
||||
- (FBLPromise<FIRCrashlyticsReport *> *)checkForUnsentReports {
|
||||
bool expectedCalled = NO;
|
||||
if (!atomic_compare_exchange_strong(&_checkForUnsentReportsCalled, &expectedCalled, YES)) {
|
||||
FIRCLSErrorLog(@"checkForUnsentReports should only be called once per execution.");
|
||||
return [FBLPromise resolvedWith:@NO];
|
||||
FIRCLSErrorLog(@"Either checkForUnsentReports or checkAndUpdateUnsentReports should be called "
|
||||
@"once per execution.");
|
||||
return [FBLPromise resolvedWith:nil];
|
||||
}
|
||||
return _unsentReportsAvailable;
|
||||
}
|
||||
|
@ -306,6 +234,10 @@ static void (^reportSentCallback)(void);
|
|||
NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate];
|
||||
[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]) {
|
||||
return [FBLPromise resolvedWith:@NO];
|
||||
}
|
||||
|
@ -314,26 +246,11 @@ static void (^reportSentCallback)(void);
|
|||
FIRCLSDebugLog(@"Root: %@", [_fileManager rootPath]);
|
||||
#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]) {
|
||||
return [FBLPromise resolvedWith:@NO];
|
||||
}
|
||||
|
||||
// Grab existing reports
|
||||
BOOL launchFailure = [self checkForAndCreateLaunchMarker];
|
||||
NSArray *preexistingReportPaths = _fileManager.activePathContents;
|
||||
BOOL launchFailure = [self.launchMarker checkForAndCreateLaunchMarker];
|
||||
|
||||
FIRCLSInternalReport *report = [self setupCurrentReport:executionIdentifier];
|
||||
if (!report) {
|
||||
|
@ -345,14 +262,6 @@ static void (^reportSentCallback)(void);
|
|||
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)];
|
||||
|
||||
if ([self.dataArbiter isCrashlyticsCollectionEnabled]) {
|
||||
|
@ -360,64 +269,43 @@ static void (^reportSentCallback)(void);
|
|||
FIRCLSDebugLog(@"Unsent reports will be uploaded at startup");
|
||||
FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken];
|
||||
|
||||
[self beginSettingsAndOnboardingWithToken:dataCollectionToken waitForSettingsRequest:NO];
|
||||
[self beginSettingsWithToken:dataCollectionToken];
|
||||
|
||||
[self beginReportUploadsWithToken:dataCollectionToken
|
||||
preexistingReportPaths:preexistingReportPaths
|
||||
blockingSend:launchFailure
|
||||
report:report];
|
||||
[self beginReportUploadsWithToken:dataCollectionToken blockingSend:launchFailure];
|
||||
|
||||
// If data collection is enabled, the SDK will not notify the user
|
||||
// when unsent reports are available, or respect Send / DeleteUnsentReports
|
||||
[_unsentReportsAvailable fulfill:@NO];
|
||||
[_unsentReportsAvailable fulfill:nil];
|
||||
|
||||
} else {
|
||||
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
|
||||
// work below has been made async and moved to the dispatch queue, maybe we can move this code
|
||||
// to the dispatch queue as well.
|
||||
int unsentReportsCount = [self unsentReportsCountWithPreexisting:preexistingReportPaths];
|
||||
if (unsentReportsCount > 0) {
|
||||
FIRCLSDebugLog(
|
||||
@"[Crashlytics:Crash] %d unsent reports are available. Checking for upload permission.",
|
||||
unsentReportsCount);
|
||||
// Wait for an action to get sent, either from processReports: or automatic data collection.
|
||||
promise = [[self waitForReportAction]
|
||||
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];
|
||||
// Wait for an action to get sent, either from processReports: or automatic data collection.
|
||||
promise = [[self waitForReportAction]
|
||||
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.
|
||||
// For the legacy report endpoint, wait on settings if orgID is not available.
|
||||
BOOL waitForSetting =
|
||||
!self.settings.shouldUseNewReportEndpoint && !self.settings.orgID;
|
||||
[self beginSettingsWithToken:dataCollectionToken];
|
||||
|
||||
[self beginSettingsAndOnboardingWithToken:dataCollectionToken
|
||||
waitForSettingsRequest:waitForSetting];
|
||||
[self beginReportUploadsWithToken:dataCollectionToken blockingSend:NO];
|
||||
|
||||
[self beginReportUploadsWithToken:dataCollectionToken
|
||||
preexistingReportPaths:preexistingReportPaths
|
||||
blockingSend:NO
|
||||
report:report];
|
||||
|
||||
} else if (action == FIRCLSReportActionDelete) {
|
||||
FIRCLSDebugLog(@"Deleting unsent reports.");
|
||||
[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];
|
||||
}
|
||||
} else if (action == FIRCLSReportActionDelete) {
|
||||
FIRCLSDebugLog(@"Deleting unsent reports.");
|
||||
[self.existingReportManager deleteUnsentReports];
|
||||
} else {
|
||||
FIRCLSErrorLog(@"Unknown report action: %d", action);
|
||||
}
|
||||
return @(report != nil);
|
||||
}];
|
||||
}
|
||||
|
||||
if (report != nil) {
|
||||
|
@ -435,52 +323,42 @@ static void (^reportSentCallback)(void);
|
|||
NSOperationQueue *__weak queue = _operationQueue;
|
||||
FBLPromise *__weak unsentReportsHandled = _unsentReportsHandled;
|
||||
promise = [promise then:^id _Nullable(NSNumber *_Nullable value) {
|
||||
[queue waitUntilAllOperationsAreFinished];
|
||||
// Signal that to callers of processReports that everything is finished.
|
||||
[unsentReportsHandled fulfill:nil];
|
||||
return value;
|
||||
FBLPromise *allOpsFinished = [FBLPromise pendingPromise];
|
||||
[queue addOperationWithBlock:^{
|
||||
[allOpsFinished fulfill:nil];
|
||||
}];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
- (void)checkAndRotateInstallUUIDIfNeededWithReport:(FIRCLSInternalReport *)report {
|
||||
[self.installIDModel regenerateInstallIDIfNeededWithBlock:^(BOOL didRotate) {
|
||||
if (!didRotate) {
|
||||
return;
|
||||
}
|
||||
|
||||
FIRCLSContextUpdateMetadata(report, self.settings, self.installIDModel, self->_fileManager);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)beginSettingsAndOnboardingWithToken:(FIRCLSDataCollectionToken *)token
|
||||
waitForSettingsRequest:(BOOL)waitForSettings {
|
||||
- (void)beginSettingsWithToken:(FIRCLSDataCollectionToken *)token {
|
||||
if (self.settings.isCacheExpired) {
|
||||
// This method can be called more than once if the user calls
|
||||
// SendUnsentReports again, so don't repeat the settings fetch
|
||||
static dispatch_once_t settingsFetchOnceToken;
|
||||
dispatch_once(&settingsFetchOnceToken, ^{
|
||||
[self.settingsAndOnboardingManager beginSettingsAndOnboardingWithGoogleAppId:self.googleAppID
|
||||
token:token
|
||||
waitForCompletion:waitForSettings];
|
||||
[self.settingsManager beginSettingsWithGoogleAppId:self.googleAppID token:token];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beginReportUploadsWithToken:(FIRCLSDataCollectionToken *)token
|
||||
preexistingReportPaths:(NSArray *)preexistingReportPaths
|
||||
blockingSend:(BOOL)blockingSend
|
||||
report:(FIRCLSInternalReport *)report {
|
||||
blockingSend:(BOOL)blockingSend {
|
||||
if (self.settings.collectReportsEnabled) {
|
||||
[self processExistingReportPaths:preexistingReportPaths
|
||||
dataCollectionToken:token
|
||||
asUrgent:blockingSend];
|
||||
[self handleContentsInOtherReportingDirectoriesWithToken:token];
|
||||
[self.existingReportManager sendUnsentReportsWithToken:token asUrgent:blockingSend];
|
||||
|
||||
} else {
|
||||
FIRCLSInfoLog(@"Collect crash reports is disabled");
|
||||
[self deleteUnsentReportsWithPreexisting:preexistingReportPaths];
|
||||
[self.existingReportManager deleteUnsentReports];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,13 +368,13 @@ static void (^reportSentCallback)(void);
|
|||
return NO;
|
||||
}
|
||||
|
||||
if (!FIRCLSContextInitialize(report, self.settings, self.installIDModel, _fileManager)) {
|
||||
if (!FIRCLSContextInitialize(report, self.settings, _fileManager)) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
[self setupStateNotifications];
|
||||
[self.notificationManager registerNotificationListener];
|
||||
|
||||
[self registerAnalyticsEventListener];
|
||||
[self.analyticsManager registerAnalyticsListener];
|
||||
|
||||
[self crashReportingSetupCompleted:mark];
|
||||
|
||||
|
@ -507,7 +385,9 @@ static void (^reportSentCallback)(void);
|
|||
// check our handlers
|
||||
FIRCLSDispatchAfter(2.0, dispatch_get_main_queue(), ^{
|
||||
FIRCLSExceptionCheckHandlers((__bridge void *)(self));
|
||||
#if CLS_SIGNAL_SUPPORTED
|
||||
FIRCLSSignalCheckHandlers();
|
||||
#endif
|
||||
#if CLS_MACH_EXCEPTION_SUPPORTED
|
||||
FIRCLSMachExceptionCheckHandlers();
|
||||
#endif
|
||||
|
@ -515,7 +395,7 @@ static void (^reportSentCallback)(void);
|
|||
|
||||
// remove the launch failure marker and record the startup time
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self removeLaunchFailureMarker];
|
||||
[self.launchMarker removeLaunchFailureMarker];
|
||||
dispatch_async(FIRCLSGetLoggingQueue(), ^{
|
||||
FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSFirstRunloopTurnTimeKey,
|
||||
[@(FIRCLSProfileEnd(mark)) description]);
|
||||
|
@ -542,26 +422,24 @@ static void (^reportSentCallback)(void);
|
|||
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;
|
||||
}
|
||||
|
||||
- (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 {
|
||||
[self createLaunchFailureMarker];
|
||||
[self.launchMarker createLaunchFailureMarker];
|
||||
|
||||
NSString *reportPath = [_fileManager setupNewPathForExecutionIdentifier:executionIdentifier];
|
||||
|
||||
|
@ -569,341 +447,4 @@ static void (^reportSentCallback)(void);
|
|||
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
|
||||
|
|
|
@ -12,24 +12,22 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "FIRCLSReportManager.h"
|
||||
#import "FIRCLSReportUploader.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h"
|
||||
|
||||
@class FIRCLSInstallIdentifierModel;
|
||||
|
||||
@interface FIRCLSReportManager () <FIRCLSReportUploaderDelegate, FIRCLSReportUploaderDataSource>
|
||||
@interface FIRCLSReportManager ()
|
||||
|
||||
@property(nonatomic, strong) NSOperationQueue *operationQueue;
|
||||
@property(nonatomic, strong) FIRCLSNetworkClient *networkClient;
|
||||
@property(nonatomic, readonly) FIRCLSReportUploader *uploader;
|
||||
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
|
||||
|
||||
@end
|
||||
|
||||
@interface FIRCLSReportManager (PrivateMethods)
|
||||
|
||||
- (BOOL)createLaunchFailureMarker;
|
||||
- (BOOL)launchFailureMarkerPresent;
|
||||
@property(nonatomic, strong) FIRCLSLaunchMarkerModel *launchMarker;
|
||||
|
||||
- (BOOL)potentiallySubmittableCrashOccurred;
|
||||
|
||||
|
|
|
@ -14,67 +14,27 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
||||
|
||||
@class FIRCLSDataCollectionToken;
|
||||
@class FIRCLSInternalReport;
|
||||
@class FIRCLSSettings;
|
||||
@class FIRCLSManagerData;
|
||||
@class FIRCLSFileManager;
|
||||
@class FIRCLSNetworkClient;
|
||||
@class FIRCLSReportUploader;
|
||||
|
||||
@protocol FIRCLSReportUploaderDelegate;
|
||||
@protocol FIRCLSReportUploaderDataSource;
|
||||
@protocol FIRAnalyticsInterop;
|
||||
|
||||
@interface FIRCLSReportUploader : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
- (instancetype)initWithQueue:(NSOperationQueue *)queue
|
||||
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;
|
||||
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property(nonatomic, readonly) NSOperationQueue *operationQueue;
|
||||
@property(nonatomic, readonly) FIRCLSNetworkClient *networkClient;
|
||||
@property(nonatomic, readonly) FIRCLSFileManager *fileManager;
|
||||
|
||||
- (BOOL)prepareAndSubmitReport:(FIRCLSInternalReport *)report
|
||||
- (void)prepareAndSubmitReport:(FIRCLSInternalReport *)report
|
||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||
asUrgent:(BOOL)urgent
|
||||
withProcessing:(BOOL)shouldProcess;
|
||||
|
||||
- (BOOL)uploadPackagedReportAtPath:(NSString *)path
|
||||
- (void)uploadPackagedReportAtPath:(NSString *)path
|
||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||
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
|
||||
|
|
|
@ -14,81 +14,89 @@
|
|||
|
||||
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
|
||||
|
||||
#import "FIRCLSApplication.h"
|
||||
#import "FIRCLSDataCollectionArbiter.h"
|
||||
#import "FIRCLSDataCollectionToken.h"
|
||||
#import "FIRCLSDefines.h"
|
||||
#import "FIRCLSFCRAnalytics.h"
|
||||
#import "FIRCLSFileManager.h"
|
||||
#import "FIRCLSInstallIdentifierModel.h"
|
||||
#import "FIRCLSInternalReport.h"
|
||||
#import "FIRCLSNetworkClient.h"
|
||||
#import "FIRCLSPackageReportOperation.h"
|
||||
#import "FIRCLSProcessReportOperation.h"
|
||||
#import "FIRCLSReportAdapter.h"
|
||||
#import "FIRCLSReportUploader_Private.h"
|
||||
#import "FIRCLSSettings.h"
|
||||
#import "FIRCLSSymbolResolver.h"
|
||||
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h"
|
||||
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
|
||||
#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h"
|
||||
#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h"
|
||||
#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h"
|
||||
|
||||
#include "FIRCLSUtility.h"
|
||||
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
|
||||
|
||||
#import "FIRCLSConstants.h"
|
||||
#import "FIRCLSMultipartMimeStreamEncoder.h"
|
||||
#import "FIRCLSURLBuilder.h"
|
||||
#import "Crashlytics/Shared/FIRCLSConstants.h"
|
||||
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSMultipartMimeStreamEncoder.h"
|
||||
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h"
|
||||
|
||||
#import <GoogleDataTransport/GDTCOREvent.h>
|
||||
#import <GoogleDataTransport/GDTCORTransport.h>
|
||||
#import <GoogleDataTransport/GoogleDataTransport.h>
|
||||
|
||||
@interface FIRCLSReportUploader () {
|
||||
id<FIRAnalyticsInterop> _analytics;
|
||||
}
|
||||
|
||||
@property(nonatomic, strong) GDTCORTransport *googleTransport;
|
||||
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
|
||||
|
||||
@property(nonatomic, readonly) NSString *googleAppID;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FIRCLSReportUploader
|
||||
|
||||
- (instancetype)initWithQueue:(NSOperationQueue *)queue
|
||||
delegate:(id<FIRCLSReportUploaderDelegate>)delegate
|
||||
dataSource:(id<FIRCLSReportUploaderDataSource>)dataSource
|
||||
client:(FIRCLSNetworkClient *)client
|
||||
fileManager:(FIRCLSFileManager *)fileManager
|
||||
analytics:(id<FIRAnalyticsInterop>)analytics {
|
||||
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_operationQueue = queue;
|
||||
_delegate = delegate;
|
||||
_dataSource = dataSource;
|
||||
_networkClient = client;
|
||||
_fileManager = fileManager;
|
||||
_analytics = analytics;
|
||||
_operationQueue = managerData.operationQueue;
|
||||
_googleAppID = managerData.googleAppID;
|
||||
_googleTransport = managerData.googleTransport;
|
||||
_installIDModel = managerData.installIDModel;
|
||||
_fileManager = managerData.fileManager;
|
||||
_analytics = managerData.analytics;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#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
|
||||
asUrgent:(BOOL)urgent
|
||||
withProcessing:(BOOL)shouldProcess {
|
||||
__block BOOL success = NO;
|
||||
|
||||
if (![dataCollectionToken isValid]) {
|
||||
FIRCLSErrorLog(@"Data collection disabled and report will not be submitted");
|
||||
return NO;
|
||||
}
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
// This activity is still relevant using GoogleDataTransport because the on-device
|
||||
// symbolication operation may be computationally intensive.
|
||||
FIRCLSApplicationActivity(
|
||||
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 (![self.fileManager moveItemAtPath:report.path
|
||||
toDirectory:self.fileManager.processingPath]) {
|
||||
|
@ -108,165 +116,101 @@
|
|||
[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
|
||||
// Check if the report has a crash file before the report is moved or deleted
|
||||
BOOL isCrash = report.isCrash;
|
||||
|
||||
if (self.dataSource.settings.shouldUseNewReportEndpoint) {
|
||||
// For the new endpoint, just move the .clsrecords from "processing" -> "prepared"
|
||||
if (![self.fileManager moveItemAtPath:report.path
|
||||
toDirectory:self.fileManager.preparedPath]) {
|
||||
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");
|
||||
}
|
||||
// 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,
|
||||
// so this can probably be removed for GoogleDataTransport.
|
||||
if (![self.fileManager moveItemAtPath:report.path
|
||||
toDirectory:self.fileManager.preparedPath]) {
|
||||
FIRCLSErrorLog(@"Unable to move report to prepared");
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog(@"[Firebase/Crashlytics] Packaged report with id '%@' for submission",
|
||||
report.identifier);
|
||||
NSString *packagedPath = [self.fileManager.preparedPath
|
||||
stringByAppendingPathComponent:report.path.lastPathComponent];
|
||||
|
||||
success = [self uploadPackagedReportAtPath:packagedPath
|
||||
dataCollectionToken:dataCollectionToken
|
||||
asUrgent:urgent];
|
||||
FIRCLSInfoLog(@"[Firebase/Crashlytics] Packaged report with id '%@' for submission",
|
||||
report.identifier);
|
||||
|
||||
// If the upload was successful and the report contained a crash forward it to Google
|
||||
// Analytics.
|
||||
if (success && isCrash) {
|
||||
[FIRCLSFCRAnalytics logCrashWithTimeStamp:report.crashedOnDate.timeIntervalSince1970
|
||||
toAnalytics:self->_analytics];
|
||||
[self uploadPackagedReportAtPath:packagedPath
|
||||
dataCollectionToken:dataCollectionToken
|
||||
asUrgent:urgent];
|
||||
|
||||
// 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
|
||||
synchronously:(BOOL)synchronous {
|
||||
FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports", "Submitting %@ %@",
|
||||
synchronous ? @"sync" : @"async", multipartmimePath);
|
||||
|
||||
if ([[[self fileManager] fileSizeAtPath:multipartmimePath] unsignedIntegerValue] == 0) {
|
||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports", @"Already-submitted report being ignored");
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSTimeInterval timeout = 10.0;
|
||||
|
||||
// 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
|
||||
/*
|
||||
* This code path can be repeated any number of times for a prepared crash report if
|
||||
* the report is failing to upload.
|
||||
*
|
||||
* Therefore, side effects (like logging to Analytics) should not go in this method or
|
||||
* else they will re-trigger when failures happen.
|
||||
*
|
||||
* When a crash report fails to upload, it will stay in the "prepared" folder. Upon next
|
||||
* run of the app, the ReportManager will attempt to re-upload prepared reports using this
|
||||
* method.
|
||||
*/
|
||||
- (void)uploadPackagedReportAtPath:(NSString *)path
|
||||
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
|
||||
asUrgent:(BOOL)urgent {
|
||||
FIRCLSDeveloperLog("Crashlytics:Crash:Reports", @"Submitting report%@",
|
||||
urgent ? @" as urgent" : @"");
|
||||
FIRCLSDebugLog(@"Submitting report %@", urgent ? @"urgently" : @"async");
|
||||
|
||||
// Check with the legacy path as the new path will always be contained in the legacy path
|
||||
BOOL isNewPreparedPath = ![path containsString:self.fileManager.legacyPreparedPath];
|
||||
|
||||
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];
|
||||
if (![dataCollectionToken isValid]) {
|
||||
FIRCLSErrorLog(@"A report upload was requested with an invalid data collection token.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Unsupported state
|
||||
return NO;
|
||||
FIRCLSReportAdapter *adapter = [[FIRCLSReportAdapter alloc] initWithPath:path
|
||||
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 {
|
||||
|
@ -278,79 +222,4 @@
|
|||
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
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "FIRCLSReportUploader.h"
|
||||
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
|
||||
|
||||
@interface FIRCLSReportUploader (PrivateMethods)
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "FIRCLSDataCollectionArbiter.h"
|
||||
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
|
||||
|
||||
#if __has_include(<FBLPromises/FBLPromises.h>)
|
||||
#import <FBLPromises/FBLPromises.h>
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
#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-
|
||||
// initialization, but can be overridden by calling [Fabric with:].
|
||||
|
@ -101,7 +101,6 @@ typedef NS_ENUM(NSInteger, FIRCLSDataCollectionSetting) {
|
|||
[firebaseCrashlyticsCollectionEnabled isKindOfClass:[NSNumber class]]) {
|
||||
return [firebaseCrashlyticsCollectionEnabled boolValue];
|
||||
}
|
||||
|
||||
return [app isDataCollectionDefaultEnabled];
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "FIRCLSDataCollectionToken.h"
|
||||
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
|
||||
|
||||
@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