diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.entitlements b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.entitlements
new file mode 100644
index 000000000..eccdd1d2b
--- /dev/null
+++ b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.entitlements
@@ -0,0 +1,8 @@
+
+
+
+
+ com.apple.developer.devicecheck.appattest-environment
+ production
+
+
diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj
index 4a3f4ad9d..14bbfcf13 100644
--- a/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj
+++ b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj
@@ -7,7 +7,20 @@
objects = {
/* Begin PBXBuildFile section */
- B9029EF126A10B1500C92F12 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */; };
+ 9A0FAF2F26E7CFD10092BADD /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF2E26E7CFD10092BADD /* FirebaseAppCheck */; };
+ 9A0FAF3126E7D1310092BADD /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF3026E7D1310092BADD /* FirebaseAppCheck */; };
+ 9A0FAF3326E7D1380092BADD /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF3226E7D1380092BADD /* FirebaseAppCheck */; };
+ 9A0FAF3626E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */; };
+ 9A0FAF3726E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */; };
+ 9A0FAF3826E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */; };
+ 9A0FAF3E26EA90340092BADD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */; };
+ 9A0FAF3F26EA90340092BADD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */; };
+ 9A0FAF4026EA90340092BADD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */; };
+ 9A0FAF4426EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */; };
+ 9A0FAF4526EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */; };
+ 9A0FAF4626EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */; };
+ 9A0FAF4A26EAB5E40092BADD /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF4926EAB5E40092BADD /* FirebaseRemoteConfig */; };
+ 9A0FAF4C26EB95E20092BADD /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF4B26EB95E20092BADD /* FirebaseAnalytics */; };
C70B63FF2696B29400851A91 /* NewPostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C70B63FE2696B29400851A91 /* NewPostsView.swift */; };
C70B64002696B29400851A91 /* NewPostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C70B63FE2696B29400851A91 /* NewPostsView.swift */; };
C730A31F26B0998A00A29E81 /* PostsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C730A31E26B0998A00A29E81 /* PostsType.swift */; };
@@ -23,9 +36,7 @@
C796F29A26CCDCF50076C5F5 /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = C796F29926CCDCF50076C5F5 /* FirebaseDatabase */; };
C796F29C26CCE3DA0076C5F5 /* ScreenDimensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C796F29B26CCE3DA0076C5F5 /* ScreenDimensions.swift */; };
C796F29D26CCE3DA0076C5F5 /* ScreenDimensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C796F29B26CCE3DA0076C5F5 /* ScreenDimensions.swift */; };
- C796F29E26CCE9DE0076C5F5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */; };
C796F2AD26D2281A0076C5F5 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C796F2AC26D2281A0076C5F5 /* Preview Assets.xcassets */; };
- C796F2B226D228380076C5F5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */; };
C796F2B326D2283B0076C5F5 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6B5B2268DAC1800546A57 /* Comment.swift */; };
C796F2B426D2283E0076C5F5 /* UserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F60CF5268EBEDE002F68AB /* UserViewModel.swift */; };
C796F2B526D228410076C5F5 /* PostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79D1AC226A4114600B6A169 /* PostViewModel.swift */; };
@@ -96,7 +107,10 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
+ 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleAppCheckProviderFactory.swift; sourceTree = ""; };
+ 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
+ 9A0FAF4126EA914D0092BADD /* DatabaseExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DatabaseExample.entitlements; sourceTree = ""; };
+ 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCustomAppCheckProvider.swift; sourceTree = ""; };
C70B63FE2696B29400851A91 /* NewPostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostsView.swift; sourceTree = ""; };
C730A31E26B0998A00A29E81 /* PostsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsType.swift; sourceTree = ""; };
C7690D8826DE0BD900F30AA6 /* UITests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -154,6 +168,7 @@
buildActionMask = 2147483647;
files = (
C796F2C526D228F30076C5F5 /* FirebaseDatabase in Frameworks */,
+ 9A0FAF3326E7D1380092BADD /* FirebaseAppCheck in Frameworks */,
C796F2C326D228F30076C5F5 /* FirebaseAuth in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -162,9 +177,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9A0FAF2F26E7CFD10092BADD /* FirebaseAppCheck in Frameworks */,
C7C6B59B268C8D7800546A57 /* FirebaseDatabase in Frameworks */,
+ 9A0FAF4C26EB95E20092BADD /* FirebaseAnalytics in Frameworks */,
C7C6B597268C8D7800546A57 /* FirebaseDatabaseSwift-Beta in Frameworks */,
C7C6B599268C8D7800546A57 /* FirebaseAuth in Frameworks */,
+ 9A0FAF4A26EAB5E40092BADD /* FirebaseRemoteConfig in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -173,6 +191,7 @@
buildActionMask = 2147483647;
files = (
C796F29A26CCDCF50076C5F5 /* FirebaseDatabase in Frameworks */,
+ 9A0FAF3126E7D1310092BADD /* FirebaseAppCheck in Frameworks */,
C796F29826CCDCEF0076C5F5 /* FirebaseAuth in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -180,6 +199,15 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 9A0FAF3426E7E37E0092BADD /* AppCheck */ = {
+ isa = PBXGroup;
+ children = (
+ 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */,
+ 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */,
+ );
+ path = AppCheck;
+ sourceTree = "";
+ };
C796F29626CCDCEF0076C5F5 /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -207,7 +235,8 @@
C7C6B56E268C8C9A00546A57 = {
isa = PBXGroup;
children = (
- B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */,
+ 9A0FAF4126EA914D0092BADD /* DatabaseExample.entitlements */,
+ 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */,
C7C6B573268C8C9A00546A57 /* Shared */,
C7C6B57D268C8C9C00546A57 /* iOS */,
C7C6B584268C8C9C00546A57 /* macOS */,
@@ -220,6 +249,7 @@
C7C6B573268C8C9A00546A57 /* Shared */ = {
isa = PBXGroup;
children = (
+ 9A0FAF3426E7E37E0092BADD /* AppCheck */,
C7C6B5A5268CED2600546A57 /* Models */,
C7C6B5A4268CED2000546A57 /* Views */,
C7C6B574268C8C9A00546A57 /* DatabaseExampleApp.swift */,
@@ -360,6 +390,7 @@
packageProductDependencies = (
C796F2C226D228F30076C5F5 /* FirebaseAuth */,
C796F2C426D228F30076C5F5 /* FirebaseDatabase */,
+ 9A0FAF3226E7D1380092BADD /* FirebaseAppCheck */,
);
productName = tvOSDatabaseExample;
productReference = C796F2A326D228180076C5F5 /* DatabaseExample (tvOS).app */;
@@ -382,6 +413,9 @@
C7C6B596268C8D7800546A57 /* FirebaseDatabaseSwift-Beta */,
C7C6B598268C8D7800546A57 /* FirebaseAuth */,
C7C6B59A268C8D7800546A57 /* FirebaseDatabase */,
+ 9A0FAF2E26E7CFD10092BADD /* FirebaseAppCheck */,
+ 9A0FAF4926EAB5E40092BADD /* FirebaseRemoteConfig */,
+ 9A0FAF4B26EB95E20092BADD /* FirebaseAnalytics */,
);
productName = "DatabaseExample (iOS)";
productReference = C7C6B57B268C8C9C00546A57 /* DatabaseExample.app */;
@@ -403,6 +437,7 @@
packageProductDependencies = (
C796F29726CCDCEF0076C5F5 /* FirebaseAuth */,
C796F29926CCDCF50076C5F5 /* FirebaseDatabase */,
+ 9A0FAF3026E7D1310092BADD /* FirebaseAppCheck */,
);
productName = "DatabaseExample (macOS)";
productReference = C7C6B583268C8C9C00546A57 /* DatabaseExample.app */;
@@ -497,7 +532,7 @@
files = (
C796F2AD26D2281A0076C5F5 /* Preview Assets.xcassets in Resources */,
C796F2C626D390010076C5F5 /* Assets.xcassets in Resources */,
- C796F2B226D228380076C5F5 /* GoogleService-Info.plist in Resources */,
+ 9A0FAF4026EA90340092BADD /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -505,8 +540,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9A0FAF3E26EA90340092BADD /* GoogleService-Info.plist in Resources */,
C7C6B58B268C8C9C00546A57 /* Assets.xcassets in Resources */,
- B9029EF126A10B1500C92F12 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -514,8 +549,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9A0FAF3F26EA90340092BADD /* GoogleService-Info.plist in Resources */,
C7C6B58C268C8C9C00546A57 /* Assets.xcassets in Resources */,
- C796F29E26CCE9DE0076C5F5 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -560,8 +595,10 @@
C796F2B926D228490076C5F5 /* NewPostsView.swift in Sources */,
C796F2BF26D228490076C5F5 /* Database+Extensions.swift in Sources */,
C796F2B326D2283B0076C5F5 /* Comment.swift in Sources */,
+ 9A0FAF3826E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */,
C796F2C026D228490076C5F5 /* DatabaseExampleApp.swift in Sources */,
C796F2B426D2283E0076C5F5 /* UserViewModel.swift in Sources */,
+ 9A0FAF4626EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */,
C796F2BD26D228490076C5F5 /* LoginView.swift in Sources */,
C796F2BB26D228490076C5F5 /* SignUpView.swift in Sources */,
C796F2BA26D228490076C5F5 /* PostCell.swift in Sources */,
@@ -582,8 +619,10 @@
C79D1AED26A8D9A300B6A169 /* PostsView.swift in Sources */,
C77ABFAE26B8A7FF00BDE919 /* Database+Extensions.swift in Sources */,
C7F60CFC268EE316002F68AB /* ContentView.swift in Sources */,
+ 9A0FAF3626E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */,
C799B60E269E1CEF00A43C40 /* PostDetailView.swift in Sources */,
C70B63FF2696B29400851A91 /* NewPostsView.swift in Sources */,
+ 9A0FAF4426EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */,
C7F60CF2268E352F002F68AB /* SignUpView.swift in Sources */,
C7C6B587268C8C9C00546A57 /* DatabaseExampleApp.swift in Sources */,
C730A31F26B0998A00A29E81 /* PostsType.swift in Sources */,
@@ -604,8 +643,10 @@
C79D1AEE26A8D9A300B6A169 /* PostsView.swift in Sources */,
C77ABFAF26B8A7FF00BDE919 /* Database+Extensions.swift in Sources */,
C7F60CFD268EE316002F68AB /* ContentView.swift in Sources */,
+ 9A0FAF3726E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */,
C799B60F269E1CEF00A43C40 /* PostDetailView.swift in Sources */,
C70B64002696B29400851A91 /* NewPostsView.swift in Sources */,
+ 9A0FAF4526EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */,
C7F60CF3268E352F002F68AB /* SignUpView.swift in Sources */,
C7C6B588268C8C9C00546A57 /* DatabaseExampleApp.swift in Sources */,
C730A32026B0998A00A29E81 /* PostsType.swift in Sources */,
@@ -955,7 +996,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = DatabaseExample.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = 374XEWX2QT;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -963,8 +1007,9 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator;
PRODUCT_NAME = DatabaseExample;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -976,7 +1021,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = DatabaseExample.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = 374XEWX2QT;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -984,8 +1032,9 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator;
PRODUCT_NAME = DatabaseExample;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -999,8 +1048,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
+ DEVELOPMENT_TEAM = 374XEWX2QT;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = macOS/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -1008,7 +1059,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator;
PRODUCT_NAME = DatabaseExample;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
@@ -1021,8 +1072,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
+ DEVELOPMENT_TEAM = 374XEWX2QT;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = macOS/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -1030,7 +1083,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator;
PRODUCT_NAME = DatabaseExample;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
@@ -1117,6 +1170,31 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
+ 9A0FAF2E26E7CFD10092BADD /* FirebaseAppCheck */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseAppCheck;
+ };
+ 9A0FAF3026E7D1310092BADD /* FirebaseAppCheck */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseAppCheck;
+ };
+ 9A0FAF3226E7D1380092BADD /* FirebaseAppCheck */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseAppCheck;
+ };
+ 9A0FAF4926EAB5E40092BADD /* FirebaseRemoteConfig */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseRemoteConfig;
+ };
+ 9A0FAF4B26EB95E20092BADD /* FirebaseAnalytics */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseAnalytics;
+ };
C796F29726CCDCEF0076C5F5 /* FirebaseAuth */ = {
isa = XCSwiftPackageProductDependency;
package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/GoogleService-Info.plist b/database/DatabaseExampleSwiftUI/DatabaseExample/GoogleService-Info.plist
deleted file mode 100644
index 9fe4b489f..000000000
--- a/database/DatabaseExampleSwiftUI/DatabaseExample/GoogleService-Info.plist
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
- AD_UNIT_ID_FOR_BANNER_TEST
- ca-app-pub-3940256099942544/2934735716
- AD_UNIT_ID_FOR_INTERSTITIAL_TEST
- ca-app-pub-3940256099942544/4411468910
- API_KEY
- AIzaSyAzlj4APqi5S58nFtE52Da0fYBOHA2MhaY
- BUNDLE_ID
- com.google.firebase.quickstart.DatabaseExample
- CLIENT_ID
- 123456789000-hjugbg6ud799v4c49dim8ce2usclthar.apps.googleusercontent.com
- DATABASE_URL
- https://mockproject-1234.firebaseio.com
- GCM_SENDER_ID
- 123456789000
- GOOGLE_APP_ID
- 1:123456789000:ios:f1bf012572b04063
- IS_ADS_ENABLED
-
- IS_ANALYTICS_ENABLED
-
- IS_APPINVITE_ENABLED
-
- IS_GCM_ENABLED
-
- IS_SIGNIN_ENABLED
-
- PLIST_VERSION
- 1
- PROJECT_ID
- mockproject-1234
- REVERSED_CLIENT_ID
- com.googleusercontent.apps.123456789000-hjugbg6ud799v4c49dim8ce2usclthar
- STORAGE_BUCKET
- mockproject-1234.appspot.com
-
-
diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/MyCustomAppCheckProvider.swift b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/MyCustomAppCheckProvider.swift
new file mode 100644
index 000000000..9810d82ed
--- /dev/null
+++ b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/MyCustomAppCheckProvider.swift
@@ -0,0 +1,128 @@
+//
+// Copyright (c) 2021 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import Foundation
+import DeviceCheck
+
+import Firebase
+
+/// The App Check provider that uses Firebase Remote Config to either forward
+/// Firebase App Check token request to the standard AppAttestProvider fail
+/// to skip attestation. The attestation provider also logs Analytics events to
+/// track if App Attest API is available on a device and if attestation
+/// succeeded or failed. The main motivation to use the custom App Check
+/// provider is to gradually enable App Attest attestation to avoid throttling
+/// form Apple backend. Another reason is tracking additional metrics with
+/// Firebase Analytics.
+/// NOTE: This is an example and may require additional optimizations to ensure the best performance in a production app, e.g. you may want to avoid fetching and activating Remote Config as a part of attestation and prefer to do it separately to avoid additional latency of the attestation process.
+class MyCustomAppCheckProvider: NSObject, AppCheckProvider {
+ let firebaseApp: FirebaseApp
+
+ init(firebaseApp: FirebaseApp) {
+ self.firebaseApp = firebaseApp
+
+ super.init()
+
+ // Log Analytics event if App Attest is available.
+ logAppAttestAvailability()
+
+ #if DEBUG
+ // Print FIS Auth token for
+ printFISToken()
+ #endif
+ }
+
+ private lazy var appAttestProvider: AppAttestProvider? = {
+ AppAttestProvider(app: self.firebaseApp)
+ }()
+
+ func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
+ // Fetch App Attest flag from remote config.
+ let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
+ remoteConfig.fetchAndActivate { remoteConfigStatus, error in
+ // Get App Attest flag value.
+ let appAttestEnabled = remoteConfig[Constants.appAttestRemoteConfigFlagName].boolValue
+
+ guard appAttestEnabled else {
+ // Skip attestation if App Attest is disabled. Another attestation method like DeviceCheck may be used instead of just skipping.
+ handler(nil, ProviderError.appAttestIsDisabled)
+ return
+ }
+
+ // Try to obtain App Attest provider instance and fail if cannot.
+ guard let appAttestProvider = self.appAttestProvider else {
+ handler(nil, ProviderError.appAttestIsUnavailable)
+ return
+ }
+
+ appAttestProvider.getToken(completion: handler)
+
+ // If App Attest is enabled for the app instance then forward the Firebase App Check token request to App Attest provider.
+ appAttestProvider.getToken { token, error in
+ // Log an analytics event to track attestation success rate and make a decision if App Attest rollout should proceed.
+ let appAttestEvent = (token != nil && error == nil) ? Constants
+ .appAttestAvailableSuccessEventName : Constants.appAttestAvailableFailureEventName
+ Analytics.logEvent(appAttestEvent, parameters: nil)
+
+ // Pass the result to the handler.
+ handler(token, error)
+ }
+ }
+ }
+
+ /// Logs an Analytics event if App Attest is available. It will be used as a trigger for the App Attest rollout A/B testing experiment.
+ private func logAppAttestAvailability() {
+ if DCAppAttestService.shared.isSupported {
+ Analytics.logEvent(Constants.appAttestAvailableEventName, parameters: nil)
+ }
+ }
+
+ /// Retrieves and prints a Firebase Installations Service (FIS) auth token.
+ /// The token can be used to assign a particular A/B testing experiment variant to a test device.
+ private func printFISToken() {
+ Installations.installations(app: firebaseApp).authToken { tokenResult, error in
+ print("FIS auth token: \(String(describing: tokenResult?.authToken))")
+ }
+ }
+
+ // A factory class to connect the custom provider to Firebase App Check.
+ class Factory: NSObject, AppCheckProviderFactory {
+ func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
+ return MyCustomAppCheckProvider(firebaseApp: app)
+ }
+ }
+}
+
+extension MyCustomAppCheckProvider {
+ /// The provider errors enum.
+ enum ProviderError: Error {
+ case appAttestIsDisabled
+ case appAttestIsUnavailable
+ }
+
+ /// Constants.
+ enum Constants {
+ /// Remote Config flag name for enabling/disabling App Attest.
+ static let appAttestRemoteConfigFlagName = "AppAttestEnabled"
+
+ /// Analytics event name to log if App Attest is available on the device.
+ static let appAttestAvailableEventName = "AppAttestAvailable"
+ /// Analytics event name to log when App Attest attestation succeeds.
+ static let appAttestAvailableSuccessEventName = "AppAttestSuccess"
+ /// Analytics event name to log when App Attest attestation fails.
+ static let appAttestAvailableFailureEventName = "AppAttestFailure"
+ }
+}
diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/SimpleAppCheckProviderFactory.swift b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/SimpleAppCheckProviderFactory.swift
new file mode 100644
index 000000000..4bf35e7a0
--- /dev/null
+++ b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/SimpleAppCheckProviderFactory.swift
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2021 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import Foundation
+import Firebase
+
+class SimpleAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
+ func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
+ #if targetEnvironment(simulator)
+ // App Attest is not available on simulators.
+ // Use a debug provider.
+ let provider = AppCheckDebugProvider(app: app)
+
+ // Print only locally generated token to avoid a valid token leak on CI.
+ print("Firebase App Check debug token: \(provider?.localDebugToken() ?? "")")
+
+ return provider
+ #else
+ if #available(iOS 14.0, *) {
+ // Use App Attest provider on real devices.
+ return MyCustomAppCheckProvider(app: app)
+ } else {
+ return DeviceCheckProvider(app: app)
+ }
+ #endif
+ }
+}
diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift
index f40e832e7..fe1bd7ffb 100644
--- a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift
+++ b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift
@@ -20,6 +20,9 @@ import Firebase
@main
struct DatabaseExampleApp: App {
init() {
+ // Set an instance of `MyAppCheckProviderFactory` as an App Check provider factory before
+ // configuring Firebase.
+ AppCheck.setAppCheckProviderFactory(MyCustomAppCheckProvider.Factory())
FirebaseApp.configure()
}