From f48cb82a2512756fa9464e4a46567ad1b60062c9 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 12:10:46 +0100 Subject: [PATCH 01/30] Add CI workflow, build instructions, and agent guidelines - Introduced CI workflow for build and package validation using GitHub Actions. - Added detailed building instructions for local development in `docs/BUILDING.md`. - Created `AGENTS.md` to outline agent instructions and best practices for contributions. - Updated `Readme.md` to include CI and publishing information. - Enhanced `CONTRIBUTING.md` with guidelines for new contributors and repository orientation. --- .config/dotnet-tools.json | 13 ++++++++++ .github/workflows/ci.yml | 52 +++++++++++++++++++++++++++++++++++++++ AGENTS.md | 18 ++++++++++++++ CONTRIBUTING.md | 51 +++++++++++++++++++++++++++++++++++++- Readme.md | 5 ++++ docs/BUILDING.md | 43 ++++++++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 .config/dotnet-tools.json create mode 100644 .github/workflows/ci.yml create mode 100644 AGENTS.md create mode 100644 docs/BUILDING.md diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 000000000..650869bae --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "0.38.5", + "commands": [ + "dotnet-cake" + ] + } + } +} + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..ace86e6bb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + inputs: + names: + description: "Cake --names (comma-separated)" + required: false + default: "Google.SignIn" + +permissions: + contents: read + +jobs: + build: + runs-on: macos-14 + env: + CAKE_NAMES: ${{ inputs.names || 'Google.SignIn' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET (global.json) + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Restore .NET workloads + run: dotnet workload restore Xamarin.Google.sln + + - name: Install CocoaPods + run: | + if ! command -v pod >/dev/null 2>&1; then + sudo gem install cocoapods + fi + pod --version + + - name: Restore tools + run: dotnet tool restore + + - name: Build + pack + run: dotnet tool run dotnet-cake -- --target=nuget --names="${CAKE_NAMES}" + + - name: Upload packages + uses: actions/upload-artifact@v4 + with: + name: nuget + path: output/*.nupkg diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..980051eac --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,18 @@ +# Agent Instructions (public OSS) + +## Non-negotiables +- Documentation and samples must be generic (not app-specific). +- Do not reference private business context. +- Do not commit secrets; samples must rely on local config templates. + +## Working agreements +- Keep changes reviewable and releaseable (small PR-sized diffs). +- Prefer minimal disruption to existing package IDs and build scripts. + +## Quick commands +- Build and pack a single component (macOS): + - `dotnet tool restore` + - `dotnet tool run dotnet-cake -- --target=nuget --names=Google.SignIn` + +## CI +- GitHub Actions should run build/pack validation without requiring any app secrets (publishing uses the built-in `GITHUB_TOKEN`). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73a2706cc..965f82b55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,4 +4,53 @@ * Each PR should be as focused as possible. * Do not include unnecessary white space changes in your PR! If someone wants to make a pass standardizing white space project-wide, that can be its own PR. Otherwise, follow the convention of each individual file. If your IDE insists on changing formatting, just don't commit it! * Do not update .NET targets/versions. I intend to keep the project backwards compatible with legacy Xamarin and .NET6 until April 2025 at least. -* For large changes, open an issue first to discuss it. \ No newline at end of file +* For large changes, open an issue first to discuss it. + +## Read this first + +If you’re new to native bindings: please open a new discussion and don’t hesitate to create a draft PR early. It’s much easier to align on the approach before spending time iterating on build tooling, Pod dependency constraints, or API surface decisions. + +For local build instructions and commands, see `docs/BUILDING.md`. + +## What you’re contributing + +This repo primarily contains: + +* **Bindings** (C# API surface + native frameworks packaged into NuGet) +* **Build automation** (Cake scripts that fetch/build Pods and pack NuGets) +* **Samples** (small apps to validate the bindings work end-to-end) +* **Docs** (how to build, validate, publish) + +Most contributions fall into one of these buckets: + +* **Docs-only**: clarify setup, sample configuration, gotchas. +* **Dependency bumps**: update a Pod version (and any required transitive Pods), then ensure the binding still packs and the sample still builds. +* **Binding fixes**: API surface adjustments, linker/NativeReference fixes, or changes needed after a native SDK update. + +## Repository orientation (quick map) + +* `components.cake`: component definitions (Pod specs, sample names, dependency graph). +* `externals/`: generated/native artifacts produced from Pods (created by the build). +* `source/`: binding projects (what becomes NuGet packages). +* `samples/`: sample apps that reference the bindings. +* `.github/workflows/`: CI validation and publishing. + +## Common pitfalls with iOS bindings + +* **Pod constraints are not NuGet constraints**: if a Pod update pulls a new transitive dependency, you usually need to declare it explicitly in `components.cake` so the build remains deterministic. +* **Minimum deployment target**: some Pods require a higher iOS deployment target; this can surface as CocoaPods resolution errors or build failures. +* **Signing vs build-only**: device builds require provisioning; CI should validate “build-only” (no signing) where possible. +* **URL scheme callbacks**: OAuth-style flows often require `Info.plist` URL scheme changes in addition to config files. + +## Validation checklist (before requesting review) + +At minimum, validate the component(s) you touched: + +* `dotnet tool restore` +* `dotnet tool run dotnet-cake -- --target=nuget --names=` +* `dotnet tool run dotnet-cake -- --target=samples --names=` + +Also: + +* Keep samples and docs **generic** (no app-specific context). +* Do not commit secrets or service configuration files; prefer `.template` files and document the required local steps. diff --git a/Readme.md b/Readme.md index f2883083c..bfe302bbe 100644 --- a/Readme.md +++ b/Readme.md @@ -5,6 +5,11 @@ This was a really unfortunate decision from Microsoft. Having these extremely co Microsoft's current recommendation to iOS.NET developers is that they should write their own bindings using this [slim binding demo project](https://github.com/Redth/DotNet.Platform.SlimBindings) as a guide. However, developers following this approach can find their 'slim bindings' to be incompatible with any other published libraries with dependency conflicts, such as Plugin.Firebase. +## CI and publishing + +- Local build instructions: `docs/BUILDING.md` +- GitHub Packages publishing workflow (NuGet): `docs/PUBLISHING_GITHUB_PACKAGES.md` + # Contributing & Sponsoring As a community-supported continuation, I'm happy to review any PRs to help move this project forward. These libraries almost certainly have some missing or stale bindings. Work needs to happen to keep these bindings current with native SDKs. Whole artifacts still need to be converted from where Microsoft left them. Sample projects need to be updated (or rewritten). Tests would be nice. diff --git a/docs/BUILDING.md b/docs/BUILDING.md new file mode 100644 index 000000000..c8e2f187a --- /dev/null +++ b/docs/BUILDING.md @@ -0,0 +1,43 @@ +# Building locally (macOS) + +This repo builds .NET iOS/macOS bindings and NuGet packages using Cake. + +## Prerequisites + +- .NET SDK (see `global.json`) +- Xcode (matching the installed iOS workload requirements) +- CocoaPods (`pod`) + +Restore the local Cake tool (any version `< 1.0` should work): + +```sh +dotnet tool restore +``` + +## Build + pack a component + +Build and produce `.nupkg` files into `./output`: + +```sh +dotnet tool run dotnet-cake -- --target=nuget --names=Google.SignIn +``` + +## Build samples (using source) + +Build sample projects (without publishing packages): + +```sh +dotnet tool run dotnet-cake -- --target=samples --names=Google.SignIn +``` + +### Configure the Google Sign-In sample + +For a runnable sign-in flow on iOS, the app must register an URL scheme callback. When you provide your own `GoogleService-Info.plist` (or fill in `samples/Google/SignIn/SignInExample/GoogleService-Info.plist.template`), also update `samples/Google/SignIn/SignInExample/Info.plist` so `CFBundleURLSchemes` matches your `REVERSED_CLIENT_ID`. + +## Clean-up + +To clean generated folders: + +```sh +dotnet tool run dotnet-cake -- --target=clean +``` From a2079dfee012790e24b77f87cf9a3c260a6526a3 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 12:11:04 +0100 Subject: [PATCH 02/30] Add GitHub Actions workflow for publishing NuGet packages and update README files --- .github/workflows/publish-github-packages.yml | 53 +++++++++++++++++++ docs/NUGET_README.md | 20 +++++++ docs/PUBLISHING_GITHUB_PACKAGES.md | 31 +++++++++++ .../GTMSessionFetcher.csproj | 2 + .../GoogleUtilities/GoogleUtilities.csproj | 2 + .../Google/PromisesObjC/PromisesObjC.csproj | 2 + source/Google/SignIn/SignIn.csproj | 2 + 7 files changed, 112 insertions(+) create mode 100644 .github/workflows/publish-github-packages.yml create mode 100644 docs/NUGET_README.md create mode 100644 docs/PUBLISHING_GITHUB_PACKAGES.md diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml new file mode 100644 index 000000000..3c6d437ee --- /dev/null +++ b/.github/workflows/publish-github-packages.yml @@ -0,0 +1,53 @@ +name: Publish (GitHub Packages) + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + names: + description: "Cake --names (comma-separated)" + required: false + default: "Google.SignIn" + +permissions: + contents: read + packages: write + +jobs: + publish: + runs-on: macos-14 + env: + CAKE_NAMES: ${{ inputs.names || 'Google.SignIn' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET (global.json) + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Restore .NET workloads + run: dotnet workload restore Xamarin.Google.sln + + - name: Install CocoaPods + run: | + if ! command -v pod >/dev/null 2>&1; then + sudo gem install cocoapods + fi + pod --version + + - name: Restore tools + run: dotnet tool restore + + - name: Build + pack + run: dotnet tool run dotnet-cake -- --target=nuget --names="${CAKE_NAMES}" + + - name: Push packages + run: | + dotnet nuget push "output/*.nupkg" \ + --source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ + --api-key "${{ secrets.GITHUB_TOKEN }}" \ + --skip-duplicate diff --git a/docs/NUGET_README.md b/docs/NUGET_README.md new file mode 100644 index 000000000..24916b790 --- /dev/null +++ b/docs/NUGET_README.md @@ -0,0 +1,20 @@ +# Overview + +This package is part of a set of .NET bindings for Google and Firebase native iOS SDKs. + +## Target frameworks + +These packages are intended for iOS and Mac Catalyst TFMs (for example `net8.0-ios`, `net9.0-ios`, `net10.0-ios`). + +When multi-targeting, condition the reference so it only restores for iOS: + +```xml + + + +``` + +## Notes on native dependency conflicts + +Google/Firebase iOS SDKs share native dependencies (xcframeworks). Avoid mixing multiple independent bindings that ship overlapping Google/Firebase native SDK binaries in the same app, as it can lead to duplicate symbols or runtime issues. + diff --git a/docs/PUBLISHING_GITHUB_PACKAGES.md b/docs/PUBLISHING_GITHUB_PACKAGES.md new file mode 100644 index 000000000..db7b3c1ea --- /dev/null +++ b/docs/PUBLISHING_GITHUB_PACKAGES.md @@ -0,0 +1,31 @@ +# Publishing to GitHub Packages (NuGet) + +This repository can publish `.nupkg` files to GitHub Packages (NuGet feed) via GitHub Actions. + +## How publishing works + +- A tag push triggers the publish workflow. +- The workflow builds and packs NuGet packages. +- Optionally, you can run the workflow manually (`workflow_dispatch`) and pass a custom Cake `--names` value. +- The workflow pushes packages to: + - `https://nuget.pkg.github.com//index.json` + +## Consuming packages + +Add GitHub Packages as a NuGet source and authenticate using a GitHub PAT (or workflow token in CI). + +Notes: +- The publish workflow uses the built-in `GITHUB_TOKEN` (no extra repository secret is required). +- Local development typically uses a GitHub PAT with `read:packages` (and `repo` for private repos). + +Create a local `NuGet.Config` (or update your existing one) and add: + +```xml + + + + + +``` + +Then restore using credentials for the `` account. diff --git a/source/Google/GTMSessionFetcher/GTMSessionFetcher.csproj b/source/Google/GTMSessionFetcher/GTMSessionFetcher.csproj index 9aed43c7e..c329ed470 100644 --- a/source/Google/GTMSessionFetcher/GTMSessionFetcher.csproj +++ b/source/Google/GTMSessionFetcher/GTMSessionFetcher.csproj @@ -24,6 +24,7 @@ © Microsoft Corporation. All rights reserved. © 2024, Adam Essenmacher. https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md + NUGET_README.md true 3.5.0.5 @@ -34,6 +35,7 @@ + diff --git a/source/Google/GoogleUtilities/GoogleUtilities.csproj b/source/Google/GoogleUtilities/GoogleUtilities.csproj index 155f83a79..9ff0a7a85 100644 --- a/source/Google/GoogleUtilities/GoogleUtilities.csproj +++ b/source/Google/GoogleUtilities/GoogleUtilities.csproj @@ -24,6 +24,7 @@ © Microsoft Corporation. All rights reserved. © 2024, Adam Essenmacher. https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md + NUGET_README.md true 8.1.0.3 @@ -34,6 +35,7 @@ + diff --git a/source/Google/PromisesObjC/PromisesObjC.csproj b/source/Google/PromisesObjC/PromisesObjC.csproj index e3a939f66..311fc8a7a 100644 --- a/source/Google/PromisesObjC/PromisesObjC.csproj +++ b/source/Google/PromisesObjC/PromisesObjC.csproj @@ -24,6 +24,7 @@ © Microsoft Corporation. All rights reserved. © 2024, Adam Essenmacher. https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md + NUGET_README.md true 2.4.0.5 @@ -34,6 +35,7 @@ + diff --git a/source/Google/SignIn/SignIn.csproj b/source/Google/SignIn/SignIn.csproj index be643e076..687a15008 100644 --- a/source/Google/SignIn/SignIn.csproj +++ b/source/Google/SignIn/SignIn.csproj @@ -24,6 +24,7 @@ googleiossignin_128x128.png https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md + NUGET_README.md true 8.0.0.4 @@ -38,6 +39,7 @@ + From 594ff0dd971ac7f3df2de366933849fc9b3d7d42 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 17:21:07 +0100 Subject: [PATCH 03/30] Add AppCheckCore package and wire SignIn to it --- source/Google/AppCheckCore/ApiDefinition.cs | 4 ++ .../Google/AppCheckCore/AppCheckCore.csproj | 49 +++++++++++++++++++ .../Google/AppCheckCore/AppCheckCore.targets | 5 ++ source/Google/AppCheckCore/License.md | 15 ++++++ source/Google/SignIn/SignIn.csproj | 8 +-- 5 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 source/Google/AppCheckCore/ApiDefinition.cs create mode 100644 source/Google/AppCheckCore/AppCheckCore.csproj create mode 100644 source/Google/AppCheckCore/AppCheckCore.targets create mode 100644 source/Google/AppCheckCore/License.md diff --git a/source/Google/AppCheckCore/ApiDefinition.cs b/source/Google/AppCheckCore/ApiDefinition.cs new file mode 100644 index 000000000..8696e80b7 --- /dev/null +++ b/source/Google/AppCheckCore/ApiDefinition.cs @@ -0,0 +1,4 @@ +using System; +namespace Google.AppCheckCore +{ +} diff --git a/source/Google/AppCheckCore/AppCheckCore.csproj b/source/Google/AppCheckCore/AppCheckCore.csproj new file mode 100644 index 000000000..2dad4caff --- /dev/null +++ b/source/Google/AppCheckCore/AppCheckCore.csproj @@ -0,0 +1,49 @@ + + + net9.0-ios;net10.0-ios;net9.0-maccatalyst;net10.0-maccatalyst + enable + true + true + true + 15.0 + Google.AppCheckCore + Google.AppCheckCore + 11.2.0.0 + 11.2.0.0 + Resources + true + true + + + AdamE.Google.iOS.AppCheckCore + AppCheckCore + AppCheckCore packed for .NET for iOS + AppCheckCore packed for .NET for iOS + Microsoft, Adam Essenmacher, Jean-Emmanuel Baillat + Adam Essenmacher + © Microsoft Corporation. All rights reserved. © 2026, Adam Essenmacher. + https://github.com/AdamEssenmacher/GoogleApisForiOSComponents + License.md + true + 11.2.0.0 + + + + + + + + + + + + Framework + True + True + DeviceCheck + + + + + + diff --git a/source/Google/AppCheckCore/AppCheckCore.targets b/source/Google/AppCheckCore/AppCheckCore.targets new file mode 100644 index 000000000..6c569a53e --- /dev/null +++ b/source/Google/AppCheckCore/AppCheckCore.targets @@ -0,0 +1,5 @@ + + + <_GoogleAppCheckCoreAssemblyName>Google.AppCheckCore, Version=11.2.0.0, Culture=neutral, PublicKeyToken=null + + diff --git a/source/Google/AppCheckCore/License.md b/source/Google/AppCheckCore/License.md new file mode 100644 index 000000000..1dc43853b --- /dev/null +++ b/source/Google/AppCheckCore/License.md @@ -0,0 +1,15 @@ +**This project is not responsible for, nor does it grant any licenses to, third-party packages. Some packages may require or install dependencies which are governed by additional licenses.** + +Note: This component depends on [Firebase App Check for iOS](https://firebase.google.com/docs/app-check/ios/overview), which is subject to the [Terms of Service for Firebase Services](https://firebase.google.com/terms/). + +### .NET iOS bindings for Firebase App Check + +**The MIT License (MIT)** + +Copyright (c) .NET Foundation Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/source/Google/SignIn/SignIn.csproj b/source/Google/SignIn/SignIn.csproj index 687a15008..9f7df2272 100644 --- a/source/Google/SignIn/SignIn.csproj +++ b/source/Google/SignIn/SignIn.csproj @@ -50,13 +50,6 @@ SafariServices AuthenticationServices - - - Framework - True - True - DeviceCheck - Framework True @@ -82,5 +75,6 @@ + From c0f12f3ef85553a10d497da82679abf46b2be80d Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 17:21:33 +0100 Subject: [PATCH 04/30] Modernize Firebase.AppCheck to 12.5.0.4 line --- source/Firebase/AppCheck/AppCheck.csproj | 27 ++++++++++------------- source/Firebase/AppCheck/AppCheck.targets | 5 +++++ source/Firebase/AppCheck/License.md | 8 +++---- 3 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 source/Firebase/AppCheck/AppCheck.targets diff --git a/source/Firebase/AppCheck/AppCheck.csproj b/source/Firebase/AppCheck/AppCheck.csproj index fd3bed340..8d3638602 100644 --- a/source/Firebase/AppCheck/AppCheck.csproj +++ b/source/Firebase/AppCheck/AppCheck.csproj @@ -1,32 +1,32 @@ - + - xamarin.ios10;net6.0-ios - true + net9.0-ios;net10.0-ios;net9.0-maccatalyst;net10.0-maccatalyst enable true true true - 11.0 + 15.0 Firebase.AppCheck Firebase.AppCheck - 1.0.0.0 - 8.10.0 + 12.5.0.4 + 12.5.0.4 Resources true + true AdamE.Firebase.iOS.AppCheck Firebase APIs App Check iOS Library C# bindings for Firebase APIs App Check iOS Library C# bindings for Firebase APIs App Check iOS Library - Microsoft, Adam Essenmacher + Microsoft, Adam Essenmacher, Jean-Emmanuel Baillat Adam Essenmacher - © Microsoft Corporation. All rights reserved. © 2024, Adam Essenmacher. + © Microsoft Corporation. All rights reserved. © 2026, Adam Essenmacher. firebaseiosappcheck_128x128.png https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md true - 8.10.0 + 12.5.0.4 @@ -35,6 +35,8 @@ + + @@ -46,14 +48,9 @@ -ObjC - - - - - - + diff --git a/source/Firebase/AppCheck/AppCheck.targets b/source/Firebase/AppCheck/AppCheck.targets new file mode 100644 index 000000000..c7a149153 --- /dev/null +++ b/source/Firebase/AppCheck/AppCheck.targets @@ -0,0 +1,5 @@ + + + <_FirebaseAppCheckAssemblyName>Firebase.AppCheck, Version=12.5.0.4, Culture=neutral, PublicKeyToken=null + + diff --git a/source/Firebase/AppCheck/License.md b/source/Firebase/AppCheck/License.md index bbed91285..1dc43853b 100644 --- a/source/Firebase/AppCheck/License.md +++ b/source/Firebase/AppCheck/License.md @@ -1,8 +1,8 @@ -**Xamarin is not responsible for, nor does it grant any licenses to, third-party packages. Some packages may require or install dependencies which are governed by additional licenses.** +**This project is not responsible for, nor does it grant any licenses to, third-party packages. Some packages may require or install dependencies which are governed by additional licenses.** -Note: This component depends on [Firebase App Check for iOS](https://firebase.google.com/docs/analytics/ios/start), which is subject to the [Terms of Service for Firebase Services](https://firebase.google.com/terms/). +Note: This component depends on [Firebase App Check for iOS](https://firebase.google.com/docs/app-check/ios/overview), which is subject to the [Terms of Service for Firebase Services](https://firebase.google.com/terms/). -### Xamarin Component for Firebase App Distribution for iOS +### .NET iOS bindings for Firebase App Check **The MIT License (MIT)** @@ -13,5 +13,3 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -20160910 From 682cfd1615b700c8e2b195fe8effe56d1218e6ba Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 17:21:46 +0100 Subject: [PATCH 05/30] Enable AppCheck and AppCheckCore artifacts in Cake --- components.cake | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/components.cake b/components.cake index 0aa5377d8..866cb0f55 100644 --- a/components.cake +++ b/components.cake @@ -14,7 +14,7 @@ Artifact FIREBASE_PERFORMANCE_MONITORING_ARTIFACT = new Artifact ("Firebase.Per Artifact FIREBASE_REMOTE_CONFIG_ARTIFACT = new Artifact ("Firebase.RemoteConfig", "12.5.0.4", "15.0", ComponentGroup.Firebase, csprojName: "RemoteConfig"); Artifact FIREBASE_STORAGE_ARTIFACT = new Artifact ("Firebase.Storage", "12.5.0.4", "15.0", ComponentGroup.Firebase, csprojName: "Storage"); //Artifact FIREBASE_APP_DISTRIBUTION_ARTIFACT = new Artifact ("Firebase.AppDistribution", "8.10.0.1", "15.0", ComponentGroup.Firebase, csprojName: "AppDistribution"); -//Artifact FIREBASE_APP_CHECK_ARTIFACT = new Artifact ("Firebase.AppCheck", "8.10.0.1", "15.0", ComponentGroup.Firebase, csprojName: "AppCheck"); +Artifact FIREBASE_APP_CHECK_ARTIFACT = new Artifact ("Firebase.AppCheck", "12.5.0.4", "15.0", ComponentGroup.Firebase, csprojName: "AppCheck"); // Google artifacts available to be built. These artifacts generate NuGets. Artifact GOOGLE_ANALYTICS_ARTIFACT = new Artifact ("Google.Analytics", "3.20.0.2", "15.0", ComponentGroup.Google, csprojName: "Analytics"); @@ -24,6 +24,7 @@ Artifact GOOGLE_MOBILE_ADS_ARTIFACT = new Artifact ("Google.Mobil Artifact GOOGLE_UMP_ARTIFACT = new Artifact ("Google.UserMessagingPlatform", "1.1.0.1", "15.0", ComponentGroup.Google, csprojName: "UserMessagingPlatform"); Artifact GOOGLE_PLACES_ARTIFACT = new Artifact ("Google.Places", "7.4.0.2", "15.0", ComponentGroup.Google, csprojName: "Places"); Artifact GOOGLE_SIGN_IN_ARTIFACT = new Artifact ("Google.SignIn", "8.0.0.4", "15.0", ComponentGroup.Google, csprojName: "SignIn"); +Artifact GOOGLE_APP_CHECK_CORE_ARTIFACT = new Artifact ("Google.AppCheckCore", "11.2.0.0", "15.0", ComponentGroup.Google, csprojName: "AppCheckCore"); Artifact GOOGLE_TAG_MANAGER_ARTIFACT = new Artifact ("Google.TagManager", "7.4.0.2", "15.0", ComponentGroup.Google, csprojName: "TagManager"); Artifact GOOGLE_GOOGLE_APP_MEASUREMENT_ARTIFACT = new Artifact ("Google.AppMeasurement", "12.5.0.4", "15.0", ComponentGroup.Google, csprojName: "GoogleAppMeasurement"); @@ -64,7 +65,7 @@ var ARTIFACTS = new Dictionary { { "Firebase.RemoteConfig", FIREBASE_REMOTE_CONFIG_ARTIFACT }, { "Firebase.Storage", FIREBASE_STORAGE_ARTIFACT }, // { "Firebase.AppDistribution", FIREBASE_APP_DISTRIBUTION_ARTIFACT }, - // { "Firebase.AppCheck", FIREBASE_APP_CHECK_ARTIFACT }, + { "Firebase.AppCheck", FIREBASE_APP_CHECK_ARTIFACT }, { "Google.GoogleAppMeasurement", GOOGLE_GOOGLE_APP_MEASUREMENT_ARTIFACT }, { "Google.Analytics", GOOGLE_ANALYTICS_ARTIFACT }, @@ -73,8 +74,9 @@ var ARTIFACTS = new Dictionary { { "Google.MobileAds", GOOGLE_MOBILE_ADS_ARTIFACT }, { "Google.UserMessagingPlatform", GOOGLE_UMP_ARTIFACT }, { "Google.Places", GOOGLE_PLACES_ARTIFACT }, - { "Google.SignIn", GOOGLE_SIGN_IN_ARTIFACT }, - { "Google.TagManager", GOOGLE_TAG_MANAGER_ARTIFACT }, + { "Google.SignIn", GOOGLE_SIGN_IN_ARTIFACT }, + { "Google.AppCheckCore", GOOGLE_APP_CHECK_CORE_ARTIFACT }, + { "Google.TagManager", GOOGLE_TAG_MANAGER_ARTIFACT }, { "Google.GTMSessionFetcher", GOOGLE_GTM_SESSION_FETCHER_ARTIFACT }, { "Google.PromisesObjC", GOOGLE_PROMISES_OBJC_ARTIFACT }, { "Google.Nanopb", GOOGLE_NANOPB_ARTIFACT }, @@ -113,7 +115,7 @@ void SetArtifactsDependencies () FIREBASE_REMOTE_CONFIG_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT, FIREBASE_AB_TESTING_ARTIFACT }; FIREBASE_STORAGE_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_DATABASE_ARTIFACT, GOOGLE_GTM_SESSION_FETCHER_ARTIFACT /* Needed for sample FIREBASE_AUTH_ARTIFACT */ }; // FIREBASE_APP_DISTRIBUTION_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT }; - // FIREBASE_APP_CHECK_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT }; + FIREBASE_APP_CHECK_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT }; GOOGLE_ANALYTICS_ARTIFACT.Dependencies = null; GOOGLE_CAST_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT }; @@ -121,8 +123,9 @@ void SetArtifactsDependencies () GOOGLE_MOBILE_ADS_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT }; GOOGLE_UMP_ARTIFACT.Dependencies = null; GOOGLE_PLACES_ARTIFACT.Dependencies = null; - GOOGLE_SIGN_IN_ARTIFACT.Dependencies = new [] { GOOGLE_GTM_SESSION_FETCHER_ARTIFACT, GOOGLE_PROMISES_OBJC_ARTIFACT, GOOGLE_GOOGLE_UTILITIES_ARTIFACT }; + GOOGLE_SIGN_IN_ARTIFACT.Dependencies = new [] { GOOGLE_GTM_SESSION_FETCHER_ARTIFACT, GOOGLE_PROMISES_OBJC_ARTIFACT, GOOGLE_GOOGLE_UTILITIES_ARTIFACT, GOOGLE_APP_CHECK_CORE_ARTIFACT }; GOOGLE_TAG_MANAGER_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT, FIREBASE_ANALYTICS_ARTIFACT }; + GOOGLE_APP_CHECK_CORE_ARTIFACT.Dependencies = null; GOOGLE_PROMISES_OBJC_ARTIFACT.Dependencies = null; GOOGLE_GTM_SESSION_FETCHER_ARTIFACT.Dependencies = null; GOOGLE_NANOPB_ARTIFACT.Dependencies = null; @@ -209,9 +212,9 @@ void SetArtifactsPodSpecs () // FIREBASE_APP_DISTRIBUTION_ARTIFACT.PodSpecs = new [] { // PodSpec.Create ("Firebase", "8.10.0", frameworkSource: FrameworkSource.Pods, frameworkName: "FirebaseAppDistribution", targetName: "FirebaseAppDistribution", subSpecs: new [] { "AppDistribution" }) // }; - // FIREBASE_APP_CHECK_ARTIFACT.PodSpecs = new [] { - // PodSpec.Create ("Firebase", "8.10.0", frameworkSource: FrameworkSource.Pods, frameworkName: "FirebaseAppCheck", targetName: "FirebaseAppCheck", subSpecs: new [] { "AppCheck" }) - // }; + FIREBASE_APP_CHECK_ARTIFACT.PodSpecs = new [] { + PodSpec.Create ("FirebaseAppCheck", "12.5.0", frameworkSource: FrameworkSource.Pods) + }; // Google components GOOGLE_ANALYTICS_ARTIFACT.PodSpecs = new [] { @@ -233,10 +236,12 @@ void SetArtifactsPodSpecs () PodSpec.Create ("GooglePlaces", "7.4.0") }; GOOGLE_SIGN_IN_ARTIFACT.PodSpecs = new [] { - PodSpec.Create ("GoogleSignIn", "8.0.0", frameworkSource: FrameworkSource.Pods), - PodSpec.Create ("AppAuth", "1.7.6", frameworkSource: FrameworkSource.Pods), + PodSpec.Create ("GoogleSignIn", "8.0.0", frameworkSource: FrameworkSource.Pods), + PodSpec.Create ("AppAuth", "1.7.6", frameworkSource: FrameworkSource.Pods), + PodSpec.Create ("GTMAppAuth", "4.1.1", frameworkSource: FrameworkSource.Pods), + }; + GOOGLE_APP_CHECK_CORE_ARTIFACT.PodSpecs = new [] { PodSpec.Create ("AppCheckCore", "11.2.0", frameworkSource: FrameworkSource.Pods), - PodSpec.Create ("GTMAppAuth", "4.1.1", frameworkSource: FrameworkSource.Pods), }; GOOGLE_TAG_MANAGER_ARTIFACT.PodSpecs = new [] { PodSpec.Create ("GoogleTagManager", "7.4.0") From 09d6cccbb85a31ff2fe139961bcc28e013cb56f3 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 19:06:18 +0100 Subject: [PATCH 06/30] ci: bootstrap publish AppCheckCore before Cake --- .github/workflows/publish-github-packages.yml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml index 3c6d437ee..68c12eef8 100644 --- a/.github/workflows/publish-github-packages.yml +++ b/.github/workflows/publish-github-packages.yml @@ -29,6 +29,15 @@ jobs: with: global-json-file: global.json + - name: Configure GitHub Packages NuGet source (this repo owner) + run: | + dotnet nuget remove source "github-owner" >/dev/null 2>&1 || true + dotnet nuget add source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ + --name "github-owner" \ + --username "${{ github.actor }}" \ + --password "${{ secrets.GITHUB_TOKEN }}" \ + --store-password-in-clear-text + - name: Restore .NET workloads run: dotnet workload restore Xamarin.Google.sln @@ -42,6 +51,35 @@ jobs: - name: Restore tools run: dotnet tool restore + - name: Bootstrap AppCheckCore (required by Google.SignIn / Firebase.AppCheck) + run: | + set -euo pipefail + + if [[ "${CAKE_NAMES}" != *"Google.SignIn"* && "${CAKE_NAMES}" != *"Firebase.AppCheck"* && "${CAKE_NAMES}" != *"Google.AppCheckCore"* ]]; then + echo "Skipping bootstrap; CAKE_NAMES=${CAKE_NAMES}" + exit 0 + fi + + mkdir -p output + + # Build externals (produces externals/AppCheckCore.xcframework) + dotnet tool run dotnet-cake -- --target=externals --names="Google.AppCheckCore" + + # Pack the AppCheckCore NuGet without restoring the entire solution + dotnet pack "./source/Google/AppCheckCore/AppCheckCore.csproj" \ + -c Release \ + -o "./output" + + # Push AppCheckCore first so subsequent restore can resolve it + dotnet nuget push "output/AdamE.Google.iOS.AppCheckCore.*.nupkg" \ + --source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ + --api-key "${{ secrets.GITHUB_TOKEN }}" \ + --skip-duplicate + + # Avoid propagation delays within the same job + dotnet nuget remove source "bootstrap-output" >/dev/null 2>&1 || true + dotnet nuget add source "${PWD}/output" --name "bootstrap-output" + - name: Build + pack run: dotnet tool run dotnet-cake -- --target=nuget --names="${CAKE_NAMES}" From 598daea7ea3bda73c0ab6a51bf2e4690e268e8c7 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 19:50:54 +0100 Subject: [PATCH 07/30] Add step to un-quarantine built frameworks before packaging --- .github/workflows/publish-github-packages.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml index 68c12eef8..3337cffeb 100644 --- a/.github/workflows/publish-github-packages.yml +++ b/.github/workflows/publish-github-packages.yml @@ -80,6 +80,10 @@ jobs: dotnet nuget remove source "bootstrap-output" >/dev/null 2>&1 || true dotnet nuget add source "${PWD}/output" --name "bootstrap-output" + - name: Un-quarantine built frameworks + run: | + sudo xattr -dr com.apple.quarantine externals || true + - name: Build + pack run: dotnet tool run dotnet-cake -- --target=nuget --names="${CAKE_NAMES}" From 16a76787ade1cb6d103a57805e9597b4f90a3cee Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 20:21:48 +0100 Subject: [PATCH 08/30] Update build settings to disable code signing for Xcode frameworks --- .github/workflows/publish-github-packages.yml | 8 +++++++- common.cake | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml index 3337cffeb..562c9a67c 100644 --- a/.github/workflows/publish-github-packages.yml +++ b/.github/workflows/publish-github-packages.yml @@ -17,13 +17,19 @@ permissions: jobs: publish: - runs-on: macos-14 + runs-on: macos-15 env: CAKE_NAMES: ${{ inputs.names || 'Google.SignIn' }} steps: - name: Checkout uses: actions/checkout@v4 + - name: Toolchain versions + run: | + xcodebuild -version + swift --version + xcode-select -p + - name: Setup .NET (global.json) uses: actions/setup-dotnet@v4 with: diff --git a/common.cake b/common.cake index ef9ca73ae..4a6d07e39 100644 --- a/common.cake +++ b/common.cake @@ -345,6 +345,14 @@ void BuildXcodeFatFramework (FilePath xcodeProject, PodSpec [] podSpecs, Platfor workingDirectory = workingDirectory ?? Directory("./externals/"); buildSettings = buildSettings ?? new Dictionary (); + if (!buildSettings.ContainsKey("CODE_SIGNING_ALLOWED")) + buildSettings["CODE_SIGNING_ALLOWED"] = "NO"; + if (!buildSettings.ContainsKey("CODE_SIGNING_REQUIRED")) + buildSettings["CODE_SIGNING_REQUIRED"] = "NO"; + if (!buildSettings.ContainsKey("CODE_SIGN_IDENTITY")) + buildSettings["CODE_SIGN_IDENTITY"] = ""; + if (!buildSettings.ContainsKey("EXPANDED_CODE_SIGN_IDENTITY")) + buildSettings["EXPANDED_CODE_SIGN_IDENTITY"] = ""; foreach (var podSpec in podSpecs) { var target = podSpec.TargetName; @@ -423,6 +431,14 @@ void BuildXcodeXcframework (FilePath xcodeProject, PodSpec [] podSpecs, Platform workingDirectory = workingDirectory ?? Directory ("./externals/"); buildSettings = buildSettings ?? new Dictionary (); + if (!buildSettings.ContainsKey("CODE_SIGNING_ALLOWED")) + buildSettings["CODE_SIGNING_ALLOWED"] = "NO"; + if (!buildSettings.ContainsKey("CODE_SIGNING_REQUIRED")) + buildSettings["CODE_SIGNING_REQUIRED"] = "NO"; + if (!buildSettings.ContainsKey("CODE_SIGN_IDENTITY")) + buildSettings["CODE_SIGN_IDENTITY"] = ""; + if (!buildSettings.ContainsKey("EXPANDED_CODE_SIGN_IDENTITY")) + buildSettings["EXPANDED_CODE_SIGN_IDENTITY"] = ""; foreach (var podSpec in podSpecs) { Information ($"Building the following framework: {podSpec.FrameworkName}..."); From 3d2a79c358c863767446238a6780e2a68cdf4955 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 20:53:59 +0100 Subject: [PATCH 09/30] ci: pin dotnet 10.0.100 and stabilize externals build --- .github/workflows/publish-github-packages.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml index 562c9a67c..c3b6ef588 100644 --- a/.github/workflows/publish-github-packages.yml +++ b/.github/workflows/publish-github-packages.yml @@ -20,6 +20,10 @@ jobs: runs-on: macos-15 env: CAKE_NAMES: ${{ inputs.names || 'Google.SignIn' }} + # Pin the .NET SDK selection to the exact global.json version (avoid rolling forward to a broken patch). + DOTNET_ROLL_FORWARD: Disable + # Avoid picking up any preinstalled SDKs outside DOTNET_ROOT. + DOTNET_MULTILEVEL_LOOKUP: 0 steps: - name: Checkout uses: actions/checkout@v4 @@ -35,6 +39,16 @@ jobs: with: global-json-file: global.json + - name: Verify .NET SDK selection + run: | + dotnet --version + dotnet --info + dotnet --list-sdks + if [[ "$(dotnet --version)" != "10.0.100" ]]; then + echo "ERROR: Expected .NET SDK 10.0.100 (global.json) but got $(dotnet --version)." + exit 1 + fi + - name: Configure GitHub Packages NuGet source (this repo owner) run: | dotnet nuget remove source "github-owner" >/dev/null 2>&1 || true From a6510a62ce757954c9f1e628d38093cccee05ca5 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 21:03:03 +0100 Subject: [PATCH 10/30] ci: enforce .NET SDK version 10.0.100 and update build scripts for consistency --- .github/workflows/ci.yml | 12 ++++++++++-- .github/workflows/publish-github-packages.yml | 11 +++-------- build.cake | 7 ++++--- global.json | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ace86e6bb..58d98ba26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,10 +24,18 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup .NET (global.json) + - name: Setup .NET SDK 10.0.100 (exact) uses: actions/setup-dotnet@v4 with: - global-json-file: global.json + dotnet-version: '10.0.100' + + - name: Verify .NET SDK + run: | + dotnet --version + if [[ "$(dotnet --version)" != "10.0.100" ]]; then + echo "ERROR: Expected .NET SDK 10.0.100 but got $(dotnet --version)." + exit 1 + fi - name: Restore .NET workloads run: dotnet workload restore Xamarin.Google.sln diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml index c3b6ef588..9c8e84462 100644 --- a/.github/workflows/publish-github-packages.yml +++ b/.github/workflows/publish-github-packages.yml @@ -20,10 +20,6 @@ jobs: runs-on: macos-15 env: CAKE_NAMES: ${{ inputs.names || 'Google.SignIn' }} - # Pin the .NET SDK selection to the exact global.json version (avoid rolling forward to a broken patch). - DOTNET_ROLL_FORWARD: Disable - # Avoid picking up any preinstalled SDKs outside DOTNET_ROOT. - DOTNET_MULTILEVEL_LOOKUP: 0 steps: - name: Checkout uses: actions/checkout@v4 @@ -34,18 +30,17 @@ jobs: swift --version xcode-select -p - - name: Setup .NET (global.json) + - name: Setup .NET SDK 10.0.100 (exact) uses: actions/setup-dotnet@v4 with: - global-json-file: global.json + dotnet-version: '10.0.100' - name: Verify .NET SDK selection run: | dotnet --version dotnet --info - dotnet --list-sdks if [[ "$(dotnet --version)" != "10.0.100" ]]; then - echo "ERROR: Expected .NET SDK 10.0.100 (global.json) but got $(dotnet --version)." + echo "ERROR: Expected .NET SDK 10.0.100 but got $(dotnet --version)." exit 1 fi diff --git a/build.cake b/build.cake index 093fca5a0..68cd75992 100644 --- a/build.cake +++ b/build.cake @@ -55,7 +55,8 @@ Setup (context => { IS_LOCAL_BUILD = string.IsNullOrWhiteSpace (EnvironmentVariable ("AGENT_ID")); Information ($"Is a local build? {IS_LOCAL_BUILD}"); - BACKSLASH = IS_LOCAL_BUILD ? @"\" : @"\"; + // Always use forward slashes for MSBuild targets on all platforms + BACKSLASH = "/"; }); Task("build") @@ -174,7 +175,7 @@ Task ("libs") }; foreach (var target in SOURCES_TARGETS) - msBuildSettings.Targets.Add($@"source\{target}"); + msBuildSettings.Targets.Add($"source/{target}"); DotNetCoreBuild(SOLUTION_PATH, dotNetCoreBuildSettings); }); @@ -191,7 +192,7 @@ Task ("samples") }; foreach (var target in SAMPLES_TARGETS) - msBuildSettings.Targets.Add($@"samples-using-source\{target}"); + msBuildSettings.Targets.Add($"samples-using-source/{target}"); DotNetCoreBuild(SOLUTION_PATH, dotNetCoreBuildSettings); }); diff --git a/global.json b/global.json index 16d716cb5..aed87f724 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "10.0.100", - "rollForward": "latestPatch" + "rollForward": "disable" } } From 1485c742e4263bddaeb3b5bfb58f72988b3b711b Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 22:55:24 +0100 Subject: [PATCH 11/30] ci: update .NET SDK setup to use global.json and improve build scripts --- .github/workflows/ci.yml | 12 +---- .github/workflows/publish-github-packages.yml | 46 +------------------ build.cake | 40 ++++++++++------ docs/BUILDING.md | 17 +++++++ global.json | 2 +- 5 files changed, 48 insertions(+), 69 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58d98ba26..561970ce7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,18 +24,10 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup .NET SDK 10.0.100 (exact) + - name: Setup .NET SDK uses: actions/setup-dotnet@v4 with: - dotnet-version: '10.0.100' - - - name: Verify .NET SDK - run: | - dotnet --version - if [[ "$(dotnet --version)" != "10.0.100" ]]; then - echo "ERROR: Expected .NET SDK 10.0.100 but got $(dotnet --version)." - exit 1 - fi + global-json-file: global.json - name: Restore .NET workloads run: dotnet workload restore Xamarin.Google.sln diff --git a/.github/workflows/publish-github-packages.yml b/.github/workflows/publish-github-packages.yml index 9c8e84462..154891050 100644 --- a/.github/workflows/publish-github-packages.yml +++ b/.github/workflows/publish-github-packages.yml @@ -30,19 +30,10 @@ jobs: swift --version xcode-select -p - - name: Setup .NET SDK 10.0.100 (exact) + - name: Setup .NET SDK uses: actions/setup-dotnet@v4 with: - dotnet-version: '10.0.100' - - - name: Verify .NET SDK selection - run: | - dotnet --version - dotnet --info - if [[ "$(dotnet --version)" != "10.0.100" ]]; then - echo "ERROR: Expected .NET SDK 10.0.100 but got $(dotnet --version)." - exit 1 - fi + global-json-file: global.json - name: Configure GitHub Packages NuGet source (this repo owner) run: | @@ -66,39 +57,6 @@ jobs: - name: Restore tools run: dotnet tool restore - - name: Bootstrap AppCheckCore (required by Google.SignIn / Firebase.AppCheck) - run: | - set -euo pipefail - - if [[ "${CAKE_NAMES}" != *"Google.SignIn"* && "${CAKE_NAMES}" != *"Firebase.AppCheck"* && "${CAKE_NAMES}" != *"Google.AppCheckCore"* ]]; then - echo "Skipping bootstrap; CAKE_NAMES=${CAKE_NAMES}" - exit 0 - fi - - mkdir -p output - - # Build externals (produces externals/AppCheckCore.xcframework) - dotnet tool run dotnet-cake -- --target=externals --names="Google.AppCheckCore" - - # Pack the AppCheckCore NuGet without restoring the entire solution - dotnet pack "./source/Google/AppCheckCore/AppCheckCore.csproj" \ - -c Release \ - -o "./output" - - # Push AppCheckCore first so subsequent restore can resolve it - dotnet nuget push "output/AdamE.Google.iOS.AppCheckCore.*.nupkg" \ - --source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ - --api-key "${{ secrets.GITHUB_TOKEN }}" \ - --skip-duplicate - - # Avoid propagation delays within the same job - dotnet nuget remove source "bootstrap-output" >/dev/null 2>&1 || true - dotnet nuget add source "${PWD}/output" --name "bootstrap-output" - - - name: Un-quarantine built frameworks - run: | - sudo xattr -dr com.apple.quarantine externals || true - - name: Build + pack run: dotnet tool run dotnet-cake -- --target=nuget --names="${CAKE_NAMES}" diff --git a/build.cake b/build.cake index 68cd75992..e82a0379c 100644 --- a/build.cake +++ b/build.cake @@ -167,34 +167,42 @@ Task ("libs") .IsDependentOn("ci-setup") .Does(() => { - var msBuildSettings = new DotNetCoreMSBuildSettings (); var dotNetCoreBuildSettings = new DotNetCoreBuildSettings { Configuration = "Release", Verbosity = DotNetCoreVerbosity.Diagnostic, - MSBuildSettings = msBuildSettings + NoRestore = false }; - foreach (var target in SOURCES_TARGETS) - msBuildSettings.Targets.Add($"source/{target}"); - - DotNetCoreBuild(SOLUTION_PATH, dotNetCoreBuildSettings); + // Build each artifact's csproj directly instead of using solution targets + foreach (var artifact in ARTIFACTS_TO_BUILD) { + var csprojPath = $"./source/{artifact.ComponentGroup}/{artifact.CsprojName}/{artifact.CsprojName}.csproj"; + Information ($"Building: {csprojPath}"); + DotNetCoreBuild(csprojPath, dotNetCoreBuildSettings); + } }); Task ("samples") .IsDependentOn("libs") .Does(() => { - var msBuildSettings = new DotNetCoreMSBuildSettings (); var dotNetCoreBuildSettings = new DotNetCoreBuildSettings { Configuration = "Release", Verbosity = DotNetCoreVerbosity.Diagnostic, - MSBuildSettings = msBuildSettings + NoRestore = false }; - foreach (var target in SAMPLES_TARGETS) - msBuildSettings.Targets.Add($"samples-using-source/{target}"); - - DotNetCoreBuild(SOLUTION_PATH, dotNetCoreBuildSettings); + // Build each sample csproj directly + foreach (var artifact in ARTIFACTS_TO_BUILD) { + if (artifact.Samples == null) + continue; + foreach (var sample in artifact.Samples) { + var samplePath = $"./samples/{artifact.ComponentGroup}/{sample}/{sample}.csproj"; + if (FileExists(samplePath)) { + Information ($"Building sample: {samplePath}"); + DotNetCoreBuild(samplePath, dotNetCoreBuildSettings); + } + } + } }); Task ("nuget") @@ -211,8 +219,12 @@ Task ("nuget") Verbosity = DotNetCoreVerbosity.Diagnostic, }; - foreach (var target in SOURCES_TARGETS) - DotNetCorePack($"./source/{target}", dotNetCorePackSettings); + // Pack each artifact's csproj directly + foreach (var artifact in ARTIFACTS_TO_BUILD) { + var csprojPath = $"./source/{artifact.ComponentGroup}/{artifact.CsprojName}/{artifact.CsprojName}.csproj"; + Information ($"Packing: {csprojPath}"); + DotNetCorePack(csprojPath, dotNetCorePackSettings); + } }); Task ("clean") diff --git a/docs/BUILDING.md b/docs/BUILDING.md index c8e2f187a..e6012cce7 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -41,3 +41,20 @@ To clean generated folders: ```sh dotnet tool run dotnet-cake -- --target=clean ``` + +## Troubleshooting + +### MSB4057: The target "source/..." does not exist + +This error can occur when using MSBuild solution-level targets with certain .NET SDK versions. The `build.cake` script avoids this by building each `.csproj` directly in dependency order, which is more explicit and reliable. + +### NU1101: Unable to find package AdamE.Google.iOS.AppCheckCore + +Some packages (like `SignIn`) depend on `AppCheckCore` which is built from this repo. The Cake script handles this automatically by building dependencies first. If you still encounter this: + +1. Ensure you're using the latest `build.cake` (it should iterate `ARTIFACTS_TO_BUILD`) +2. Run the full build: `dotnet tool run dotnet-cake -- --target=nuget --names=Google.SignIn` + +### Code signing errors during xcframework build + +The Cake scripts disable code signing by default (`CODE_SIGNING_ALLOWED=NO`) for CI compatibility. If you need signed frameworks, override the build settings in `common.cake`. diff --git a/global.json b/global.json index aed87f724..16d716cb5 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "10.0.100", - "rollForward": "disable" + "rollForward": "latestPatch" } } From bc2e69646e9004c4ee4197b309d09a5e42e18c4e Mon Sep 17 00:00:00 2001 From: kapusch Date: Sun, 1 Feb 2026 23:42:22 +0100 Subject: [PATCH 12/30] feat: add Firebase App Check icons and update ApiDefinition.cs for ObjCRuntime import --- icons/firebaseiosappcheck_128x128.png | Bin 0 -> 7398 bytes icons/firebaseiosappcheck_512x512.png | Bin 0 -> 59527 bytes source/Firebase/AppCheck/ApiDefinition.cs | 1 + 3 files changed, 1 insertion(+) create mode 100644 icons/firebaseiosappcheck_128x128.png create mode 100644 icons/firebaseiosappcheck_512x512.png diff --git a/icons/firebaseiosappcheck_128x128.png b/icons/firebaseiosappcheck_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..05c4f0fc844579aff38e66ed3ed43cd26d8fc622 GIT binary patch literal 7398 zcmV$ip(Ba=+oYd z(~JHBwL)VJLS_=SFU07QRTw|-0nAARrJ8K7UI-v+;L9iU&M-vwWE^_S_# zDX<@--++JFm#sFHKSh6i+6T~9#5eF-)HgFgKSjR*UoY}RNqyr0{Sy6gz=wnMg#+|U z^w+`1l+S6OG+;XD3kT?j=x+c&XwgS!upFf49iShg-+<4HJOPm&l-={!0eU_9>yZzH z5!r}-MmqA`WS1%5(+<$<(O(DO0kw`foxwTxua_&+(+<$f(O;kTZSZYm!Ly9iE!X{? zT?6!T^w+^>WP{qg570qbJv#&RYV_B^2cnE@QadjQaVNhgXMkRf{s!b3Z+uc8c7kYrO|J+v!nFboGP-Ao@$Q z<@35}16{FpDz(YL$})8UzS(pSK-=+8$FQBE-OkX>$md|KXa^t|^Cye!j}TM<4xq7L z22EupRTz_0USEh@wN5h14=7C!t&+;ZthdciN$K>#mD!UrpeM;VPX_pDvw1Gz zIzu}g!54fOkH*+3@{0yEFRzbEjq%a9A{~Ihqg!6|d++!G^s=%B@br*mw!J|L+pm|A zOWrD@+pm#yChHDK;C^vtN~T`iEoWcaEweBFSmq`kSBI#`faMH}I4Dq>k~)H!_I2tv zi6D6jy*xH#=h=KvxmUaCZ)zpI9&Q7VUSX`x9-f!ttiI@}d?hn1g{$8yYj?g|M#ry} zf$UJz&c`WSID1k~JpG_dJ^2kOzVxVMb!sp(L~ZaJG4N)JDEbZfm#_0g2|g$ilrj(d z?~Z(Mn|+y&e%hmFg92C#vL{pfR95AG#h z^PQR5D(l|%2eRp!_k<3%Pv2Y4nmu(yCLZ{l%>Df9GMKK`*9pWE4FoxX?`q!#EDYe5 zd$7zMzy=>3qVOier`FMs{dM23|YtORLUhe_}~|0`jLN@p>$c&>I67* zVB$>BHt?yqMY=2evMrEv2RLg?5g^82;?uf z$cIfx%gO=H1HV+2x%3*@wCi3OyX2QVi&wyJe(e^y?3S-ed2qz6Tb3*M7|LaHA;=H> z`OJFReDj^MYW*cE0QN-_E2Rb5|JB07yPnL`wJTRTi$bz z6vnnMs{so$rcx@(p0E7ARA2bM4C7O5mqvR_H%xD*%9q(8Ku`7bz&}^X$od<oEox zKIXA_eP&U$ae}J3-+;@`C39;zCHbp%$@s2M>zZWiqO5WN|Cu{JE(_1zZ>If`D;0c2 zJ*5X$1HS4@p<#Fy650gs*EY)CMA@MFVdW9@E%7118xIWh!1%AV1^lze56Hg%`V%P~ z{D}d6Pu8w4IW5bTDrvUZFE)Eb8`U?0>R4s^#jLM0_@-f_E(-*}ts zz2}oMzvn)0+SmK}iKczDk49(*c~GQQ%RMcNzdrhw%mFaK7~BOt_77e2Y1w@3Z!Q{| zfSdT?J#y^6Ps`9iN$<~l5l`UJZ#qC!)pQ8s09pyOq6-AfR;g7RMa~^Jr+SEd-1vch zwh?&DR~>awVTcbP^*q0F0=`Ux$Jp1$fwo zL|Hll$JyYdJGo1|D|~d4MG8qPv7(b*mw-abAk#EpQI@g3D~~#Mq8w=i`K~&E9sRi6 zThv>;Td)40-Gx~E+|;DJc=xT6(`g@(&j&UM2$T`bSc+@Hs7srn6XQDc8t=J%yA6o@ zw&Ma?)7wBO(~w!)VHqj1{dhai)&ql47UU3G)>Q|fZLkT))b!?eNPf+Q%#KBI@#VR@ zZk4RwcjvTkKw@WAn=dG_T3OTqN61~`|I$V~+KFjaG;s_x5~<7Ue%BqqO#f;SR@M3K z?}AB*(!>w$l+wgcbn5q>yy0=5%GwP|UXSUi>y6lftt~bLV98p)csvud|3E&jlZAMg^bKJL?5eM1Ed3BTtZmgx!3| zGijfV6M!OF4qbj{j?|T>t+WAh%&V#EngejK(Y|?Wr*J{y=lWj$;oXv% z*Ee_cd2E8uV{#PmX-jPk41rVnB@g^Dis%G5u$^UTob52Ra^iX3U$Y+4|`!dHq2z05vppFaRStJUFbpRg!G5r@d zCA-}_`OL#oJ@ta5)dSRiv-u82NTxXqsZ4tNFG@P6)4L;|S)Z58hJq~E`Dl=XZ0D0_ z8I`&6wQ^)583$N6EScgnUSHh$5TY*dZi*}KQ@^VYfcEJGxwYf2Ig$2H@BO}c69i+=f!W#ppQ*+pIDr;h$eW}f?$9?AyHO{4|~3vi$Yr?4F)fjlmB zbv?o6!q|>P?amzdkvc$a>P)0z(Fu(+HjHLMg)LOe7Pjgc5p44ALN=%(xS%%QAY|>> zGB$6CG_WeuRR@4gW&xNTmTX~7gDp{Z@K8tj_#QLw!`YeQMnCGo7C69Cr`)Qo=8UK# zrf`rzZQkm1R~>-urZOXBW6{}@hqNDf2XArl6ib04j3r=42Ht6>*=~9uE0uv!b6=$G z4$01e`fZxs6$fxnyQ>_+w9}mSu;Xc9Kh}X zPQB8ZWDZa~`-)M8#a}xTA})o;g_b&{YmdOW5evJRXY-6^JJ04>?owL@yr!<71$fOS z`>j@rX629C?eKxzjN~Vn*elF^QrW;1~4Tep{xIC=G_mRA#)HjhzCu!35CQkVw6~#$T2N$@}PEf*C-q zE1hjLJmTKa=q4j+R?F;c#JUv2wf)?VF>^ZFk{3~78)y~d;ddmm0b@JN!#;UZ%8+7= zP{y$$PkE(XnE~vTI{4DLGg6$3?*zF~eHL$In|I@+*2y?4W-sy=U)SQeaJ-g^RyhOE zAW)l6YM2Fdkh65f0bKh_r%U>EuV>xtNc;JV-y*m*gIOTXd9wk38NR5A$IDZdS?^MI z4KTgR5gy%|1eel~#bOo`cS zN=`oY=Q1gJH4bIw$EuAy(?BhcJg6o!3n@jlYG$Kc@y>rV`Eh<`ruJzQ-j&VsrfH|W z`th9oaLdCQ_UTVo9ROeTtmuZwn?3l`Fmrv&@!sI*wI7t3AAiwY6*PUS0peERG2hL{ zsVE!<50MU4PnZRvIjp#PxK9d277xcm`z3w1A-(4HZZnbg=co7AuWsU%GLx(}?Dpz> zP`MAlb*BlihD`<(w>R5FzZwq!%13`DbJLTF8rXcphxG-GlmU(k+{Iu+Pf3NzS+_qoh_Z!XB!j+gDC(+0`=Qi28!g$ z+j&MH{HJRUV4`1-|45hta83V&zOJ1l6~-=*Ro8yVyrpBN-`YUX3F_b@A0x}bL}N8s zH~x)kUV&MhafuEs=q!OIt!ein&vS+_o;s@9UPT|{S_QS_tvnPU%{ znGm3G0a$+^6auuhiTw}@OcCmL+yUI^hp})%I025Sryjdg2NSo#k|lh&A$P<3Bzy51 zosRVy13RtixF$%Zd9haAp^Q#U`xSkyO;0_?-XrVBZ(0Hz7PqjKztZ!w!N%y`sMGK1*UnsSo?s0plxg~uD#Sv8bx169l$U8VH`S(4GS*(tZJnOTspf=BP(2hEQ9sPEr z;JqPL1N2-hHT|L-{J$@|BC+;UdJx^J5t$qRQ#n`E=lS)SZ$v8=h~6R*Pu+sYVZu93 z*pxhh$AEcadc8q)6!psxv-4{2rVq)5Z~TnDm6ZHLR>zIDsZbgWlkHfaCRb%p`E6Sv}R5A9|Cld*hd6%T*t#M^h3bOAF`Z+{C?l z(aD?ky+eSfiQs@@a{-1F@`4h}Ky9A#e)>E1iI|xq3k|1!Gy-(d5bruVF6Jy~gbiH! zEArak`FC5iC4P4LpqzOAD^i*Mkz`Xd#@h$<3JwRyPr2t1I^C;L3#E*thufkDYhu=`Ts?$Q?4IZ#Ll~lL-Qi0@!4O9$T?b1zRVI{q%Rl0TBJO>Hy7>?F9Hz z2qJDySJoSD{u{aQ?H_7ZHFjA=AGn)7`nZ19=V2+IeoRv3Ni*=SqH0w^$ZS^7UnhkP zH^|85Hzz*Db9H0?+^PL?_$R+7tA_MDMtTXEAC^KHzzPE_tQ>mcrj9s3v*@RRbO7vQ z2GH47H+7t9PA>cS{W7xka*DQ{R>})f)Gv9L^#24_%Cq`m%3=Lj=!j$nhxItznfqfE z{UYi9hd&~@$^jYFl`p}^41ff1yPeQx+t&a=$9}hSc8Ae*tOf8{w;`F6{a^Xr#5aoE zcKr6!1A{VDSTC#AzD9=E@07ym#WJWbh;|Bm*l_6Sf0bG+X(*9bv~Y5O4r&8GP&K>`Suu-}H{3eh8u$(kl}W%lzSc^)4d5V&+ZtiNNOq z9@OTe4w7A`#<$f0qDH@;y^ILs1iF(t@w7but=n~qZoZcA)3u!PP9OcLoc#G;N?8R8(P5n`eDnr_Hn6u2bXN>Hu+~zitylq1GpJD9|Wbt&eW!S3fHU z9{HpmuaiAS&Nh~co;mT1Og`}`$q(vR%nbM;Q@;%wcy~ibC}Z=K1E}CZZLlGW#JZH% zthPBoYtipnYi0p8s-WNx>wnl99MpUCb5F^OkK8JA=Z>KZD<(}Je@c%2^p6yL{AW=; ztZ5h1nEufN{i%Nn1{oG0b&zUuAc26I!X`gHfH&yZs%>+CB++l1&h$?Xi67n~r;qNot1Mgo*uHNn__s+ubJhc2M;ZOICc9|1y8zNrNTG!?HXl@O zyiWx|YmV0z2WTbwVK-A=ALM`o;MOQMTqVosDH9&v%nh89$=$ch#FJmtt9Z%p91{Ro(GNV#k=K_sVW9a?5;8TJF9E?J@HeEFW{=!0`%gYDn|A)8UY&cbC$tQHr;a@- z$DjIJeOmct$(gHs{AO`uu$>zf)M>-SN$4{ z^4Y;#x`=!`@j{WFs_G?7YPOvgVd4( zv>N@*z$b!!PQcj!clU7929AI)ehrMiMgQB_O|o{|TU)wa%eGyLWBkcOkIMAKeR@yf zagFw>0Unoi8TDN3tpxDVzm^=JmFSNGz72q%BVabb%s@xL4JG_ThjMjDvTLr>8#>p^ zsmFSNP zJ`HxA0Qugb!CM~~XV4$x5b6xL!DJ2@)j>(?em{9Ct!EdjWk7HKq|!tB zG}4Uz_qcPqomF1nTs}9UZ!o{0{}=-A?Uf9;c#IvFalJ_Q7IwI3#fXP3D<$e-D^vWi zsMSom@=pprn&l!2j^GY_s9Rc|S#dQV~ zvRdvPLUe|(l{h?Mq;3@3dL41&6mH&1+K=r3Nus|K;M;?2gT-}%3mRqxTh6ZU$FshF z8QsLMbY;O@t-++(1dTfZ42G|s3=n!Sd zvy*PQT^D?qyj$+pclEpSam!u(*k|8@%Gf5#$%7)f?R&Y4zhUxj`C?6vQ~i+~AZqm2 z!Dk128mxDcWz7bNdPu_tggTQ_+CmCFHXo)p!hkQg{zr0vDA8XBKWxzK0d)rqWy}j2 zY`Z>rQq~1UimT7775vL~NZAH!FrSq9Hnq!IwU@d`6X*+F1V)Me2Jr39hVe8U)aHZg z5m->0r@XDh=2^bnsBNRo2ia-&+2$#4>#%v2`_RxCAT0V5gYRQZXqI26m={{P2L#wx zQgq4Y6LhiZ3=kImT?OB-bL>2*&HKql$+LCXe3ZINA!FNU^D%5`>Hy86-xqw_2%D!t zcAm|%JdE0Pz+)OD^_voxS|8e{%{Grb=98j4EK!#A+tB~OLqN0WH{g%gp5cQr?%;DD z9rELu$GYqo@|lOattRTCepjE{UYLAXefEnK@_sz?-1d;qJh!bR`_u*Mm$bb=2MCJ( zhRBc5KtqRIdAGxExodQoyjzZaB+@AQo5{QSqv)dy^pXcf>a;%go78PzP4IPqpy;oI z&kmpyHXo%!wmjU4zuDoA+$m?SNeI39r`WwJc zYG9NBatFl*hde1{Z9cC4FnQ`G4U>0mclVRjXWMpP{qj&ASHH@i=Ky}uUq9xvVN%;D zn@?H}9nDf$2iYzublJSCn`NY}%2N-itB?7lZn^w+_6jaiC)4jd_L zu=%C1she%GucU40f5T~@8~w`){B90(AGOus0Cx1h3VwfhLEQoD=zkUb{s14ntUCas z|5fn&2mHDNF#2BwzrVn*I{>2pRq*={eB%I!{_NIK$@AKNe~v@n_Bt*3{Hx&iE&L+? Y4*}0sgFd#=%K!iX07*qoM6N<$f=zR{vj6}9 literal 0 HcmV?d00001 diff --git a/icons/firebaseiosappcheck_512x512.png b/icons/firebaseiosappcheck_512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..1391e934c1b555b4f91e345b6441e71cfeb422dd GIT binary patch literal 59527 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�J}LJMs^*aL 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Ģ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

y zs(#k4Q{L5g1o2ZtAB>wxV-DjEytFgFQma+;gZ4`~Y_UwoK&^DThqazzc*jIJnbX7rlFIKs+H9Pi8fZW$*J$6yBH!TpylN{wA}WAua63Z#~1 zHKI5ZF4^Y7Sw+%#to|-a9U;y!qgR=!c4QkQ0#65WV@T#& z##_U(rm9uqu>+b!-6n5IF*69|NSTu6PD+L88!7Eu4R72HQ{En7D``NTXjsc-Z)4wg} zeq8cubu|b-UvJFvPdk%ue=!9%TpT?IEn9)qxg$p4@me9BH11eSPVPIXXYN(puo+zY zB5YFbx-qZ)8rqpVko#D0peECq+;uti7&PaC(&!3#PY!!AE_V8L!-&J|cXe8c(b7KRx;JMUDi>DUXlvfb+ zYVBcO>Z?qbi#Ik{kV}@aoZ;(;afHCvN&z{IMDosa`S!*W5%Qi1vWypsrsXgOn*n4lu|XBSkO=?ohb8pkU4du2UVhUWZT@+&Xe zWNMZ3M}?Oq(UJ`Tv1hV$JI_)^Za9pR&IO*NV{bSJLv=k9q~*?}=9GvRhtcMp_2Lhz zE_dSL<4z5XqX9{^M^*P6(r!SQ3gERU_kj(E$s+C@^lK$OwX4#3r z11+i?(zvq)_nZOtNaKIx_X8gZSX7!Z(yER7Bg_|1dRZA@H=JI~%km$)cRKKZM@;Wl zRYrb+uwiqX8MP~y#QWWEqV1f4WTXGk2hry#&LzZc{DPcog0{)E+^=qTju((>yty1w zqfs^dSnDxdu$3mPM$aA_TOd@8#6`pf7-I7ZJ>kdl;eP473vc?Rlu_=hgNe&0-BuSU zwoqB@_NyM#ozhz60>x>Ga7LK-PAKh`H=of%apNSo^AbIeocROWRwl~$Jdm#oF&?Rt zEy{W#b(c^U4t^^YtIEbrp~yXB?N!o7^N|CoUk^21B5OlMnR`zS_p~$9;atE)uLa;t^H5M<#Z`rH`P)ldg zr*FlS58q7-)RmQ|qSP&B{6?jY3i-)Te;6T8`C2?oI3WA==nikw3w<&jZ~NKzrM-b2 zPWIm~Xq++qwV3LXhFFU`*6H-5X`4Vn9B6a%SZ`pZ}Uf(^~`=Yvq^XOHE}w$=ah z*jk0))Y*Cse$;zi1`0nQeh`v7_<#K9j2F|WJ4g+}li&R~QlJin%7`1-jWQla->c{> zx~>o`nC-Vc-`zOe4}~ZeVl7v;E$yEk6Miifc7KZ|(~*LeWGSixiJSo3h_AyBe~HDj zrEERR@0GT{4q>5DCP@EUXpr+#e)O-TvR~>VofM*R5=k=syBiW^*kLkMiGYVUlD2mp h%c=U_pT;A&%i(k0Kis~!9|iyRSlaAN`{n56e*lGu(aQh; literal 0 HcmV?d00001 diff --git a/source/Firebase/AppCheck/ApiDefinition.cs b/source/Firebase/AppCheck/ApiDefinition.cs index c3a41b3c4..6f2f0f7c7 100644 --- a/source/Firebase/AppCheck/ApiDefinition.cs +++ b/source/Firebase/AppCheck/ApiDefinition.cs @@ -1,6 +1,7 @@ using System; using Firebase.Core; using Foundation; +using ObjCRuntime; namespace Firebase.AppCheck { // typedef void (^)(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) From 5c59fdfed80b0971d17b2e5d7e8f08a2735ee5a7 Mon Sep 17 00:00:00 2001 From: kapusch Date: Mon, 2 Feb 2026 08:38:31 +0100 Subject: [PATCH 13/30] ci: update CI workflow to use macOS 15 and add toolchain version checks --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 561970ce7..6ac0b5caf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,13 +17,19 @@ permissions: jobs: build: - runs-on: macos-14 + runs-on: macos-15 env: CAKE_NAMES: ${{ inputs.names || 'Google.SignIn' }} steps: - name: Checkout uses: actions/checkout@v4 + - name: Toolchain versions + run: | + xcodebuild -version + swift --version + xcode-select -p + - name: Setup .NET SDK uses: actions/setup-dotnet@v4 with: From db2d65688fd61a4ae7d2e8e6da0727f955fa64c3 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 10:39:14 +0100 Subject: [PATCH 14/30] Firebase.AppCheck: fix provider factory binding (protocol type) --- source/Firebase/AppCheck/ApiDefinition.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/Firebase/AppCheck/ApiDefinition.cs b/source/Firebase/AppCheck/ApiDefinition.cs index 6f2f0f7c7..15c87d8ee 100644 --- a/source/Firebase/AppCheck/ApiDefinition.cs +++ b/source/Firebase/AppCheck/ApiDefinition.cs @@ -7,6 +7,8 @@ namespace Firebase.AppCheck { // typedef void (^)(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) delegate void TokenCompletionHandler (AppCheckToken token, NSError error); + interface IAppCheckProviderFactory { } + // @interface FIRAppCheck : NSObject [DisableDefaultCtor] [BaseType (typeof (NSObject), Name = "FIRAppCheck")] @@ -41,7 +43,7 @@ interface AppCheck { // +(void)setAppCheckProviderFactory:(id _Nullable)factory; [Static] [Export ("setAppCheckProviderFactory:")] - void SetAppCheckProviderFactory ([NullAllowed] AppCheckProviderFactory factory); + void SetAppCheckProviderFactory ([NullAllowed] IAppCheckProviderFactory factory); // @property (assign, nonatomic) BOOL isTokenAutoRefreshEnabled; [Export ("isTokenAutoRefreshEnabled")] From 44a5e9ba64db4a6039af14b9859a0b2b472de780 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 10:47:43 +0100 Subject: [PATCH 15/30] samples: add Firebase AppCheck sample (debug provider) --- components.cake | 2 +- .../AppCheckSample.NuGet.csproj | 73 +++++++++++ .../AppCheckSample/AppCheckSample.csproj | 77 ++++++++++++ .../AppCheck/AppCheckSample/AppDelegate.cs | 74 +++++++++++ .../AppIcon.appiconset/Contents.json | 117 ++++++++++++++++++ .../AppIcon.appiconset/Icon1024.png | Bin 0 -> 70429 bytes .../AppIcon.appiconset/Icon120.png | Bin 0 -> 3773 bytes .../AppIcon.appiconset/Icon152.png | Bin 0 -> 4750 bytes .../AppIcon.appiconset/Icon167.png | Bin 0 -> 4692 bytes .../AppIcon.appiconset/Icon180.png | Bin 0 -> 5192 bytes .../AppIcon.appiconset/Icon20.png | Bin 0 -> 1313 bytes .../AppIcon.appiconset/Icon29.png | Bin 0 -> 845 bytes .../AppIcon.appiconset/Icon40.png | Bin 0 -> 1101 bytes .../AppIcon.appiconset/Icon58.png | Bin 0 -> 1761 bytes .../AppIcon.appiconset/Icon60.png | Bin 0 -> 2537 bytes .../AppIcon.appiconset/Icon76.png | Bin 0 -> 2332 bytes .../AppIcon.appiconset/Icon80.png | Bin 0 -> 2454 bytes .../AppIcon.appiconset/Icon87.png | Bin 0 -> 2758 bytes .../AppCheckSample/Entitlements.plist | 6 + .../AppCheck/AppCheckSample/Info.plist | 42 +++++++ .../AppCheckSample/LaunchScreen.storyboard | 26 ++++ .../Firebase/AppCheck/AppCheckSample/Main.cs | 6 + .../AppCheckSample/Resources/LaunchScreen.xib | 44 +++++++ .../AppCheck/AppCheckSample/SceneDelegate.cs | 54 ++++++++ 24 files changed, 520 insertions(+), 1 deletion(-) create mode 100644 samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj create mode 100644 samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj create mode 100644 samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon1024.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon120.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon152.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon167.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon180.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon20.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon29.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon40.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon58.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon60.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon76.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon80.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon87.png create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Entitlements.plist create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Info.plist create mode 100644 samples/Firebase/AppCheck/AppCheckSample/LaunchScreen.storyboard create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Main.cs create mode 100644 samples/Firebase/AppCheck/AppCheckSample/Resources/LaunchScreen.xib create mode 100644 samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs diff --git a/components.cake b/components.cake index 866cb0f55..f9d5f5c37 100644 --- a/components.cake +++ b/components.cake @@ -426,7 +426,7 @@ void SetArtifactsSamples () FIREBASE_REMOTE_CONFIG_ARTIFACT.Samples = new [] { "RemoteConfigSample" }; FIREBASE_STORAGE_ARTIFACT.Samples = new [] { "StorageSample" }; //FIREBASE_APP_DISTRIBUTION_ARTIFACT.Samples = new [] { "AppDistributionSample" }; - //FIREBASE_APP_CHECK_ARTIFACT.Samples = new [] { "AppCheckSample" }; + FIREBASE_APP_CHECK_ARTIFACT.Samples = new [] { "AppCheckSample" }; // Google components GOOGLE_ANALYTICS_ARTIFACT.Samples = new [] { "AnalyticsSample" }; diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj new file mode 100644 index 000000000..461670af6 --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj @@ -0,0 +1,73 @@ + + + net9.0-ios + iossimulator-x64;ios-arm64 + + iossimulator-x64 + Debug + iPhoneSimulator + Exe + enable + true + 15.0 + AppCheckSample + AppCheckSample + Resources + iPhoneSimulator;iPhone + Debug;Release + false + manual + + + true + full + false + prompt + 4 + false + None + + + ios-arm64 + iPhone Developer + true + prompt + 4 + false + Entitlements.plist + SdkOnly + + + true + prompt + 4 + false + None + + + ios-arm64 + iPhone Developer + true + full + false + prompt + 4 + false + Entitlements.plist + SdkOnly + false + + + + + + + + + + + + + + + diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj new file mode 100644 index 000000000..38e177eaa --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj @@ -0,0 +1,77 @@ + + + net9.0-ios + iossimulator-x64;ios-arm64 + + iossimulator-x64 + Debug + iPhoneSimulator + Exe + enable + true + 15.0 + AppCheckSample + AppCheckSample + Resources + iPhoneSimulator;iPhone + Debug;Release + false + manual + + + true + full + false + prompt + 4 + false + None + + + ios-arm64 + iPhone Developer + true + prompt + 4 + false + Entitlements.plist + SdkOnly + + + true + prompt + 4 + false + None + + + ios-arm64 + iPhone Developer + true + full + false + prompt + 4 + false + Entitlements.plist + SdkOnly + false + + + + + + + + + + + + + + + + + + + diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs b/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs new file mode 100644 index 000000000..bf6093e82 --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs @@ -0,0 +1,74 @@ +using Xamarin.iOS.Shared.Helpers; + +namespace AppCheckSample; + +using FirebaseAppCheck = Firebase.AppCheck.AppCheck; +using FirebaseCoreApp = Firebase.Core.App; + +[Register ("AppDelegate")] +public class AppDelegate : UIApplicationDelegate { + public override UIWindow? Window { + get; + set; + } + + public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) + { + // create a new window instance based on the screen size + Window = new UIWindow (UIScreen.MainScreen.Bounds); + + // You can download your GoogleService-Info.plist file following the next link: + // https://firebase.google.com/docs/ios/setup + if (!GoogleServiceInfoPlistHelper.FileExist ()) { + Window = GoogleServiceInfoPlistHelper.CreateWindowWithFileNotFoundMessage (); + return true; + } + + FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.AppCheckDebugProviderFactory ()); + FirebaseCoreApp.Configure (); + + var vc = new UIViewController (); + vc.View!.BackgroundColor = UIColor.White; + + var statusLabel = new UILabel (new CGRect (24, 140, Window!.Frame.Width - 48, 200)) { + BackgroundColor = UIColor.White, + TextColor = UIColor.Black, + TextAlignment = UITextAlignment.Center, + Lines = 0, + Text = "Firebase App Check sample\nMode: Debug provider\nTap the button to fetch a token." + }; + + var tokenButton = UIButton.FromType (UIButtonType.System); + tokenButton.Frame = new CGRect (24, 360, Window!.Frame.Width - 48, 48); + tokenButton.SetTitle ("Fetch App Check Token", UIControlState.Normal); + tokenButton.TouchUpInside += (_, _) => { + statusLabel.Text = "Fetching App Check token..."; + FirebaseAppCheck.SharedInstance.TokenForcingRefresh (true, (token, error) => { + UIApplication.SharedApplication.BeginInvokeOnMainThread (() => { + if (error is not null) { + statusLabel.Text = $"Token request failed:\n{error.LocalizedDescription}"; + return; + } + + if (token is null || string.IsNullOrWhiteSpace (token.Token)) { + statusLabel.Text = "Token request returned an empty response."; + return; + } + + var rawToken = token.Token; + var preview = rawToken.Length > 20 ? $"{rawToken[..12]}...{rawToken[^8..]}" : rawToken; + statusLabel.Text = $"Token OK\n{preview}\nExpires: {token.ExpirationDate}"; + }); + }); + }; + + vc.View.AddSubview (statusLabel); + vc.View.AddSubview (tokenButton); + Window.RootViewController = vc; + + // make the window visible + Window.MakeKeyAndVisible (); + + return true; + } +} diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..fc9d33023 --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,117 @@ +{ + "images": [ + { + "scale": "2x", + "size": "20x20", + "idiom": "iphone", + "filename": "Icon40.png" + }, + { + "scale": "3x", + "size": "20x20", + "idiom": "iphone", + "filename": "Icon60.png" + }, + { + "scale": "2x", + "size": "29x29", + "idiom": "iphone", + "filename": "Icon58.png" + }, + { + "scale": "3x", + "size": "29x29", + "idiom": "iphone", + "filename": "Icon87.png" + }, + { + "scale": "2x", + "size": "40x40", + "idiom": "iphone", + "filename": "Icon80.png" + }, + { + "scale": "3x", + "size": "40x40", + "idiom": "iphone", + "filename": "Icon120.png" + }, + { + "scale": "2x", + "size": "60x60", + "idiom": "iphone", + "filename": "Icon120.png" + }, + { + "scale": "3x", + "size": "60x60", + "idiom": "iphone", + "filename": "Icon180.png" + }, + { + "scale": "1x", + "size": "20x20", + "idiom": "ipad", + "filename": "Icon20.png" + }, + { + "scale": "2x", + "size": "20x20", + "idiom": "ipad", + "filename": "Icon40.png" + }, + { + "scale": "1x", + "size": "29x29", + "idiom": "ipad", + "filename": "Icon29.png" + }, + { + "scale": "2x", + "size": "29x29", + "idiom": "ipad", + "filename": "Icon58.png" + }, + { + "scale": "1x", + "size": "40x40", + "idiom": "ipad", + "filename": "Icon40.png" + }, + { + "scale": "2x", + "size": "40x40", + "idiom": "ipad", + "filename": "Icon80.png" + }, + { + "scale": "1x", + "size": "76x76", + "idiom": "ipad", + "filename": "Icon76.png" + }, + { + "scale": "2x", + "size": "76x76", + "idiom": "ipad", + "filename": "Icon152.png" + }, + { + "scale": "2x", + "size": "83.5x83.5", + "idiom": "ipad", + "filename": "Icon167.png" + }, + { + "scale": "1x", + "size": "1024x1024", + "idiom": "ios-marketing", + "filename": "Icon1024.png" + } + ], + "properties": {}, + "info": { + "version": 1, + "author": "xcode" + } +} diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon1024.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon1024.png new file mode 100644 index 0000000000000000000000000000000000000000..9174c989a9c8b8a5ca133228f4ed7c173fffd2ee GIT binary patch literal 70429 zcmeFZRajh2(>6K-gA?2#xVsaa1b27W;7)KDAh-sH;O-FI-8I483GVKDp7(kG!~bkw zTfeh4Yt`zm?yj!7tNLCOuB0IO0g(U^004ZDmJ(9|06>sS5C9$)006=h5Mo1q0bNui zzW}Nxi4Fk(5rDMVXEhJtNhZRo`he%fekan;Fv2QYQhHiMczDY%oYp3J%F4>N>72R= z-1^hp(p?r-UEFIwQ#s`me58MJTFp?GwuKG)#v+ZzK-FH8BL)tmoPXOmAD@dn_injo z;9~ZW=&g}nu>%*c^PS(>S7P^`Yp6@mAKNYhvFQ?IZ zi&YdXCD1!Y%<}q~#4^yR->Fltpbnn-%2JiIG3t^+AHaca^k8>gq4td;ce2&ZK3`Wu z-@OQmlZ!_ehFK={mFYDvP|Il}9Fdj$;!a;cuSQ2f4XjeSoA(xsq%rn{xEU|1UY)#b z-%(Ko@V~ej^^(hMrLJ7~>w7vsYU>8me1F?9A1F({_=w6Vi?M2{Wy1hQLQ%tz|Iqcg zMA;J^+|UTsyeUHUM@6*@C>=sB9XH{rE=L1M8 z7PfuS7qYYBq}iK9`NM6aBl_EFY>hP^*NxM@Jb*o`jbNWwo7+Y^Azj=x-o(a-i$a ze;O4Mz^r_s?M0IuJa?Swm$A{J3E-WOZOVLGT>X%1?z=n9mU~aQhJ4LpmeKHhTM=0{ zXG2*%db`RXqBGOp+p42T$WF`lllEMwvRHHIiHcb*6TU?Q{L8&)|3TcXK|*k%!8VU* zxIW9k>h*17x^ej=I&)tKco*(k7kgwK?NwGjJEpHcm+kgm^g8QjdQ0eb&E~|W|A8{@ zlU*45aY@yDNpUN^-z+(*es*EH;(3>62hLv&U@e$7Kti2yDIfP6ks+f0le*z^?^WXc zl^4@^A(R=6a$q9%v52NARg-u-&SXc?B}VnnWcx&Ivu|SR>x}H&2EfLX^Wi)q-)R9C zg@@E$TuG7@8lPLUy*bP>;p4a0w<9~Z>S8xGhH^aW>`O$})3=n~UFp;HUH&YG)cO5M zp~pDy>CYz%t9X)$L7q~95xBMWF}GsYdfQ&PT-6`CZeb>{wk7@ZX9)-9nzTajtQ{TOR}6qN$^-Dxk#ZC~{YS1xgAw z%oPibvW@543B5CO%uj2~Lyu8Lvw-kRKa<}O8FN|8ue<3Ib%mt>s5#HXc zb9xq7{V>_XrE;$jGXY(7LM2iZh4>y0Oys7P`F*j>LAFmHU4S%oWH<#jrW$EXOCY4y zzm-+!+G`0hhDh`Q@YkBR`uo^rS{!Nz=|$Auy$pX%^Cq}F_QsSMPR}h1Gp2^slIQ-w zcJRA~YT!kduH(=E78uRMz{6##J(OG+yF6NF_SFbQurgp!1&zKwZ}96-rK=F-V{iVI z9i&Gn#W;M=@N>1S*P&r3i!~8ZY@Hb=M4(xD-mTJj~t2F;dUUn@DNwrur9Q=J1VC_vs zKE39ws@^f-O^Dw(_~J5n-B{gE@>Z&>03Vws1(7s(w5%~yy{ZzfcLT9NFS;VAohFv{ z_)4Q>_npTrG zxA%Ngx|QXn0&DF1fyCcL{A9NPTdT{)u%oU z)On3UmJrZJp~}-pc_PVOp|4_sKR3_6&`v(j<%E#@9+7n5kDY2hy|NmOq9NsZ2GcUG zy}Erm>q%xeVppy6_k=JLahTtphNe9Q>PqP-Sd@Fell{V)vl;6&wH ztFSTwK~19|l`$Y;Rkr+^Rys@B zxbh09d<{1aT_Kk#A)18TM@*>zBPn*79Yw*!^|nII zVe@8|0~$4<4l7yYST@@yFx$~p#LDzZzh{;KD9*Ivo-s)ZL5~QJ9~R^z5G^Kr`AG`-JSJOBvu;OIOvb1W zpJjPw=>jrSGD-o@vJ>AhDk$dU%bONjtoNyC=)s(?RUi8t(vH6mLl8^5pf9#Ocf*}( zxP?H>Ew<5aCQ`JhG=nHEW6B)1(b!u|z3UHIK4vZEazki+zbEg7=Gz5@6JP5&2OFmD z3tht+#KaiZY+vg%g&VmY9bI6$P6ouyh#B8I*a+{YGvQWL0GK~1N@H7=i`Ugc5RCv; zC7@A<^OzpY5@XnbXp(PUR|X}};VCI-zphvJr&jxxpycW%rLFB)Bd+N0%^=Dyd^XX2 zwR_2~>5NS-*MBgXm`dti40PVb7d~AW@PXSuHWG>*%4!_>bth;C;Za-1~RSp26SG#yskb23lTa z_s-P-WyC1e8XIE0Rn|rK4L6BCZ)2W<9rxaxL3ufXkNjoHEOKWB_YmJKtoLTE;&~im zSl`qcYVd*RZ@+rq>|1pDLW;ytOudi(hjnJ_y^$k<1;h(QhQTV+gpA={ga|M8 z{4CqjIOneql!=@^$z|K+{`WllJid%6h-if+^r;2@`B~#7G`fEmAn32p*8Q6+S9`HH zg94*AchlJNl-(X1%rkwj3-@K=+L|yYGfo3wEo*KE z5-3>6qJ#dQ>5A}`*qy)+f~}CBe#5Pqse5!GH2=-+(uSYN1Kg9 z3+3uC=g(!OJ1=nKlO&uPKskP1Wh4$ScNB5K*CI^{)UHQu)!T_xBPC)5h1mp#Y@e0_ z{*&QC{WBg?xdOHG+lJs$>P&wVWkvhh1Qyx2Jwn;H@89u}F1%tGd|b0OD>k$cRe>>t zsfLQ0i>k~+s21O&DDUntZIv`|*zsJT>d=JfCra=?JHHq?^-Gz|5`IZUZrtF}0On;> zGKvIGz#pBGhIFupXvZ;{C0i-r+sZLn_yDwNXMWOrR7N40Jv=3q=wO%7#?bEMjMd$6 zupeS`QD-7`efO3u9--r`9N-{CJ(_hv?t7x^Wt1*KL*$Wv{wTrFohJFQ2u$gjXs#K9 z8m)Fd$6S`Z%~4GJG2McI=lX&tN&|pEcTB)chGK2E>OgX5tvSW6hW)(1A5-!+e&Rs< z7IKM5dT6da<3>7PhuqPSX}&knC!K6QRtR-KTiW!++Fz2_##qsxtCE$0w9ic4Q=Wfh z?&_}!(Cn}L-jmH!SzzhQ2bX!j7V34-EGp(~d5I^ZI4k!AX~LK<)QiYKxL&0oxx3+U}GjQ|~>Ib|1vU zIhtyWchd>ApRl>K=O9QPYB(IoxRpSJBJoK_KDvJb2h7u)sR3s+qBJVX#WrY99MjQLA~C z0gR=vFC7+$H`jv+Tg+hc_;`eWq~EA~jM}>^bDf2aO)3)}jYy>KlxJ{AP`L8!wHRNQ zyxE7X%zmR#et%wb3)j(S{<;!@NQ&fXEBn&mtxhYbpZQNxA<;2C7p>;PW<8=Uf1y?U zF0fUgwIv6twTQ&iUMyLt_7Wiw46vf@a`&^^qnJ@{@aWi+K5kOS7QvAz#3+F26XWyj zx|>V>lTMvOua!?z2?1kWR_>&QJ-w}nMhTvB(2nPv(|TfYHb>^#6R7O~ zG!u8+l0MQm-a9Xvyug=f*t+I(?}d{3RHY5X&GH+WLqH;hd7T|T!L=Cnnf^4Lag-b) zU~KhC75L`74NpV#Wl3-D>@!voxc!`06-Y_@D3i1R74a#8PsKH&ru5Khn)Tx#K1mKv z)M|svs{Y8==lP<9!4{@EZ?(~FTNoueMkf@iO*Kr%k_Wv%R3b3HsSZ4R=)pUPv)I{) zIkLYmAJhOt*d+`?*di%8JC~(^7zQOxhye5Fp&eBqk!DU6L_j|A-Gm_lhY*YaM4F`Aq9UOHSdma-C$h~?kOp=T#eCoo(7FK! zzbTkOL^NO^WUOJRz>knNKYH~CgLfbe#4w;;lI4g3p#N`D>i2f@%VgO5K1&7qd!17; zZIaC7a7Iebp0oCg*|OASXF}|V?DyW?vHcznwcC)j=Ye2Urv2OnBgW{@E8`;sbZA^r z09ewfn86NocgD@0g-uPuhSfQ$W&2bW?=%;A$WZ0Mw|UnW3;B8emBq!9w$1kOeqRb4 z;{cgpIOT))#hE24iS?GaWJ413H7v9DaLy{CL-cNFsqno8oC@6cmaU0I6^b-kC`fLl zfNWog${(RR>x(Rcm5X;TxhABT_%q$~JEc@QNJz-G=Ha;XYeAaX)^snxvdjlkITBOl zK<%QI*gKHVgzI0{#-$x%@e)G@OMJ+wQ-n5%P{t=y3YDhGA?GLd6L-WHv$3{9pT^vg zQUIWm^47^Hc75T@Gm`@w_wIr(0T`^hmwye2-$3nhaOSD3yiNk()Ny+s*R<5OIzbD| zz&-iRxBD2Juf%Rz>n2*+!my+v5g{8-fpO<)ME2;ZULJMLd%ins7|S*FcwqR=K8I|U z^mGr^h;FmfQ|BSzpKla>-=nd<11-gh* zBMaS_H{@47+)6QzyQ~x1waMT-BJzb;t=DC<@7l3M=wrIhbNE)%_$k%rmuzRUD4&BX zA=jaGbCSqX{dhcTf%?V^#0%~OIv1RyF{>GF#hldbwUZrU zgq8LDml19w)Jtsez#?nhj0b;wCAsWCuKe?IW4h<1LK3bKj|&Qw?&YithzQT-khn70g`iXQL?D3W7;4|nNh}K+k_aD_eC5DrE$4o~zsrQ_2 z_Z-gHmWMDxMGHxax{<;WkAaJK7YiEm#p~`xpY|>S8d6L%{V#e7O$OF)KJ+l16H^rt zyNfa6TSNQ)Eln8^UAdbxX#A_U@LXF&iU32G0gQXT%XFEV{+@b;Aawox^R_N-l=A3H zuKdct*Q|{ktS0XGvpzO*OJi9S+w?r$NgaFU4BSz`%S7*oZJOhzww#n8c5XQS^@=}> zmlF5By7##?xk0z2=baNp~bu{@k#c=KillS7E>T-P>z12m&h?*}29#i+PupL~0PW684Oa;>_kMc)Jdut1>Gu1U`r^ADf7&zwsEWC8;h+H+$F&;j2AHE!FUD@Y(2Nw<^?p%kBgu4+@OY;a zE!U=bI!-|Uz4l6r-b@7L?Es)uB^fLm%gpS-(r!cH1L=a{p|shp&xVQz8tI1G9yp$1;d`~1DMfc88u9f zqf)eq+(Ml@bNyn#;RJ^xOD_{AZ+7O-p^>~kUJwG#JV0ttTacFTsqS{GI$8Su^RGY8 z)0g&TdU~(NYigU65n*+oCE{;f`$j+d7s!=`A_P(6_6>K!%!&F-V;<<)E zO7PL;IfDWAdyS9m?d*Z!N8I}Lc0bkLGMp(jn_wLK6{ad*`i&SaI|`!%?+|sa<56Atp_DE>Fkd?7B{Ngq9KPXun>b;A z?84IZkAywVXk2LB69eI#wsPmpvh5ctpBz4V&f6FrNcD4Abh4%n;^yF|((A;c+IAlK zIQv-a1b-VBoPTMGrE14ITOWXi|D$hkUP4ChBpU!$Ac_3)O+mZ|8eUmb_csHJE((e} zLX*E&$46wQXaEHW&T024pFNlUK>{f0 z421{Y9Y-0ALkjnKR_gER<-OX8Fog@_9ypyQqBAKnnMO#3TAvbZ(-~hn`Rf-%hb7!Z z8ByzCm<(nE(EV|9>gq|1uouAhdYTc90ZPT1Q&EK=sKV+%M(Y0oZ9?@4zzLj}_?lXi zEakP2d|fzHn~njSBSSvWm4pr@l$lBXrzu5&V?2dkH4U#CP)c$7GpDoz=IQUzRGRJW zo+XkbH$?L#$I72&dP9bYjk)X%?uPngj9s)Fm)@)Q3BCwTp+TNGGP(bg8Tf?$x60*=QExGIKjQJi@Z8E8;@w&zyxMbSk3S!nvg`I1x;l zf}ew?f()~jUdyM^d~6rDwjGKym4yMCs$^iG6pZPsm|6M8?5f^7wWcXLty_Jh8&4Jq z17kou<|Y*Z9L>!;+0S zU%EQtLHH8P3KC3crR>P7xgwk*4cflQuutxqnqu(wG*l2JWf&=6E>`wKSND>cfsgd8 zFMq$fC6M{CK)fpCXv$Bh!!y*<#3CD|SIbGZ^3^n$LP-E>96D@>j(s+aALrtXM4B!W zuvf(lIf+kn#bEHD_W;nTfo0DPd;7AXhMJ{^{gR6f)`)pNZGC}E-IvY&js`E1OjRfC zLhLh&sVZ59(l5n9z~5^A=08xcU%2R~W0{|InOi~?7It@^1|h+5@5e(_%Uk%5LL6gx zIHU?!V-o-;Jo`y8kR`Yz$+$=NZ&93zQ$ja@_UNtAt(xPcc$j&@vM_m`Gl4-*2N{~a zEW=p%p9GA--957LcxsH){5_!`TIu&?B5%|qgV7jc#7St2+r;1T>3d!Xm=64Ac&-*E zmMDkd;6=LZES1 zY7Qg(V2zOv)h4jti0f|hvHp$i(-MZ*-Hea_A*^oyFC7$Q5#-yGQ{zcbWH}9($H6k5 ziufT7V^#oqy73|lR9s<`dFbZiiZ%^eAu+NDe6C=oKJs($#jn@-b&O+Bp6hoYJelhq zQDZJjkLfE@2u!{@Bn|97sK%`--l+x>rZDp~++j{9?35^ijk}-pqCPw)?WMW}vec&p z(pA@**IkzQEc5r^wU^eiGA=eZ8Uc=K@ZFvTl* zDa*HFHU?N9fr;+wUQ>Ne(3CyhYQ%nLO@5Q5v|=lA6!-c#$%9^(JCFZvev5^Y>gfKkMxl*%N-xb1;;_|Jnycz z`})wqo8TyUdt>!lYERM^jS!e1A-EWKh+(c5}bvH`xYU^X=LUi;}3^ zi%oXDQ|;u9p$ts~Y;Ac&0$?{!(^pXnWauZZJcp1a56Z}In|e`&f7Vc>YaLb8b_ zTrI0n^>3(us=M&NE*HefO%YYD<(fRk6aM;8DJb;JXm1RAa6PyZ)ZExRAsS0uOBbIwq-3*T zHAgSX7w*S|gM}dpuiV|2(78sEDoqD;VV~toiBK5t)>%Vs%Al(5%{^bWCqsJ+t(xDk zMgu>+qamW|UfN_s>qVVDZWCOXeesH?28FlTT=Kkvy2w?GBBhX>^@R|ODsWfpEIvuT zy-t0*S6(?G-`iiaxn+Jk|1P50#0A@A0)WbAc=nI*!I}rGJ{;7pZiw127z{AYJuI5f z_XXD8`d@n8&ijwA9c5-VR7~@wyb4caG9D>wL0_!KKx-W7omsDB8j0)Mkv-j;HBp@H zEAqE;w=M1q>p!Nu!8Xyqn8#wdi{-?@lAarPSr3%oYkC2T*MH@#S86S2OpaSP$N6+T zBp^_jjwrGGUNG>fTsLQ^8c|NwM#XixPWeIrZV!FUv+k&fbFWy#z^>SORg6({C?%wN znx5O|ZpHRo3yv+FTvH#H7e)LE_=gcw+q;amsfg2=$2hn^9WCePtkhC2OSG=|TBpnG zBiAtfuF?&e7<_Os&pFx^MLaW+%H;i|vSIp5@7@RxLFrH-`-yvBqF0lNenOw$)t2)X z?RHHLp`xfv!#+>8a<*McJbZY(_Cje@)(-5QthrWALCd^h=VY_9T01!K15()nt7iRE zV@Aq)SASY^NkpRx8CNJwxmD>)Qsui>X2V-dyZx;N#dGLCJfCw}gLmdApjOA!gaR=y zV~NY~z5Cow#13qk1oo8e(&6~Ah8>yk)k*8J?0OciiK@~g@lia3j_%5?XhofS)+lwJ z^P-|#wlH0nOjg6*b+BB1|)pHi5*D2(gv3(r ziYD0Z;KSmE(J;OgZ1%Creum1f$(rm?)X1B5`-RlxkA*Ys=iW8|y;Q%lf*0f_43hj` z!XbxDok@#y5>M@e^|k|y(c;(6c)xFryJ%0pvN6&&JP& z6WpwdT9TU2a5lOuRX2Xm^3{9*mAS%uHS7H5hfJGw7wj$Lo%!M3fi2Zr?9RrrO#AdD zu8*`dT_Xn#6aS1-z;H2*jR4Osqrc+P>ny@)E zT73rfJF3OV%FMMHijE67w+fX-&X*pBt`$%8(&pmkcz+n6FCOa@hS8FIrN=IxyV9Lo z$yQOe;gSB6ws%))RZO*PD<*9u zOP)E83T+flPZ0Uz7LJ{8-}X$w{4Q(T;8hpZb#{$X{A==xYDzSh=0k>a{J8Hb#czI8 zk@?s@nK$jD^;?6lGcnhG>i(L!5x6zaQ9RPEsyT<6zxS-4c8l=6kL@Yyd(of2G$wfzC5A*@k8F*YCPLU+5mek{_Mz z!AF6(kEc+N-4CwA11e0!ifs4ufMJ>DzXZ36IxAY?=dBmW=D)I5JB7ckB9Z9f@Y~vT zJB5}<%gq*<_Id8PL5|l6#YW^{t3QD2S38lBWbVDDe_7YPL1+km74uy>W4lBF?@jfU zUg-ztg6G0Rge*puBVC&5I_6$>05fA>Je-Ppv4}pu_#Pqj)2A`Vj#z)4mWF$)yp4Cy zx6<(56+A7-!ZgDfG1;6$YC0EAUKf$LOV7MZCPVpfPL;FOOY8a^PnLfwi##rSoR;ix z$gEYFK?EtU{4-DfembkMxDBmo-IQz?m7dzV(alngJ~Mll9oV!!`B8$*P#hM_2H=oD zcAI2MvcKVoSWz4~?et=KP_8u0WIF12V!rD-XtytApX4xr;Kc7I>AFw<)HoNSXH=Gd z6|?h7IYrc9y&YKWk>kadJhz(bZDO%ACIaKy_3&{Lo!i09hL=#BMezOu0ns|U$H}qfuX$Md zpP)$tGK8djg?zDobDkZ`3BUdfCQJ-@&D%}RM|kF&M;9udLpOvNB^6jtfZ6-Lykc$i(zg9|YvesuxTJr0U`dcd;NJX;p zWm`YLLTwW499pY~`)2J#UFok*%3F3Z%wP>`p=48+^vZ%ARL(Y5J32Vm70d-V7uu3K z4uLT@_j!D}PCA|rfwpG$ibodab@z?m^zB`4{tBM_OYe)ge;{rA0X&;x*B6*Apl$an zmT@f1D8(>|u8ZA1UQ_}7t(Sv^CVZNvLS8pqQ^$W`Lj4JAbSvQtA)u5;m-|;-pP%8+ zvc`cXMoBuyDfy304(sI^Nf22@!Brv-b0d67#&%$hIVMsjQ>R<;3w5RG^h~Nx@p2Q$ z%z%SwQAUqo6>=u;Fl45ZSrWq14vgEJ6m|yFcd2blvxvDxI?#y_sQM+~nCZqoDIE#x z)+9XyrDP@54;zFG0YKIrkMX}+J|G?4eOWlWbSO*KpoUwkcvGGhXu?Q=y&unidFoFo zTW13}BzSLbvy~w?Y#-iy;aT1>l+6MCaO*b>yQHzS<8V$4`NZ7zmVVJ{9N3vK6JKeOI- z??Ey{JS+2r?Uazdc?v6SGhVqw$?0`WI^^Ah?Qp9II26fuPhp3}X-rvFZuo>=62jO2Q0CxV37^y*|Ppwgey zNB|5k!OdhCjh3{+1rlknhaFN_?)L{+r0F{y{ot>Zs>CUAvEKu&>(!r7z zc^S4^`;5nd#uC6M4>mu!m=w`7MhT(ORP}4c**bJsi!4FM;zmmDU#mI%B+zp(StFDt zeEC2&U@cb&9&$F{1X7xDOC@3sk~Y&p84?T5s%fn62Epaz$g~4sEb%3c7ZpFS5`&?d zs$&E{li?`Wl9THDXU3LVP^BOpngFosZ`!^tzyFdAHsK`{-#0Cr#NngrVFN^vF6i}% zVT!w!N|-JxqSC;M{4kWg2xkm|!QLvwvnx4}VQbi?5~s;2nmk0C1(l$8=rQZw`$|S{ z?_yx1ieNtf8vis$Swj4}f~lwxD>se^sUcX1r@G%#&Ldc|tA#Tgc3H&m8BozXc|j@< zH-WiN*DDDM%F!|cFi=S`UB^?ZVbX~@kV=6LIpY38w1CF&y)p_1Xt#z$k`HtMk_$DZ z!fr&BMYjklNIl;GL~WZ30K^?{^Vk@*Vr5zv6pn|O@2oHeprsNl;&A!`>7Y-Oi2D3G zj0$crQAw%d=FAjG`kRfC#Fzd3{d!8RXtW=0SOIjJ0g^(WvW$BY(?)l97kt-UrvKm< z=$%lq0q_s}fg8E9N!I3zQ=6LKRk7Ev`dI<^vNlG; zjb9y^4JR0DBhb17`$Jij_Mf6F=P@*>PB-xYcHb!hKzD@SvU^o$aYRtdkXrFFyfgsn z45J&+T+UA!3g(6^3ilTbFt`o!?Cc0-ge*rMQX`6v1CeerL!Py@iaNtvLg)pS6qG>t zW?2Y@;D4I>|Jq#9-hx8gwkdc)q>!(JL;z6qAP;DzTnVCouF=2{wuj@tERlbH0YGZ- zn}8A}3Y34PAw-i;|8hb8*Sn4YwGwo=|A>-8=p;n{(oi5TLR!a$2-DAoLI0`j038LVMZ#moD>fMM#)$p3xD{12Nc z3^kw?^k#l2aXB?+h@DreotVCU=t2Ue zfzb`DQDK6|mN3$kO!>5bCZ1H~yMEUv zAcYRQELu3zC(ajY%LGXbsJ$FXqj?CEgNFq#fs(+OERGOJ1YZ4};DiAM*V;O8(1ru+ z@`UFu-y2e zD{bh)^BdC(UK9%eYeU@tQupNT5fE0f826vo%PL(TX?7(pd=S*UpaQABGgN2xTL<{4 ze?B9F__Z&ajtquSnnE{uTCHtCgTjVfac!^x&YPg|PRsgKj}x?LwJ^j0TZqdu>q}DO zLWt`0&9Y=+TT;ZN_`^g>N(1-SQ<6WBLY-wDz!?SzaEA!C_XQdzqv81-BjuF_%hNL{ z!3aMVzqb@-Sdmi_>NrXe0F4n);3*fDG})X7DKms8k|5{;Mx?u%W9bA(dG$|1vxLBd8D zpx=%Q%DK2s#f2lfi$KWa^Cl^zo&^`Vtxng4lpkLF869WZiP_LZ3bb zKu}l97bB?_RmP4i2YAaq%77q#v#IoQTWa&A>?ez|WE?J;o`0ZL@5< z4CHff0R`-Wv|!>g@Y#;gwCe4e@LcXq2;TW@n?V7b@M;?H^><&>j0jkz^S^+J0rY{~ z0S?S-w4H6%3_GvOln~ta2ShIj?Ah&3T2R1%)=AH&K!bw%05MrkK;NDRsLJO+{Fkdc zT(rM{-uFNeYtSxYz!GjW4rc7fc%5`gHAcw39+-A7EBxsDEbzx*J4mSX3l$qYB`K*U z{L2<(8)VB1aD8SB{Ibaek(>olK{=-xs>(*H=#hU0KpmpTi9+ooGlqM!WTzVB6{x{O zgo2e^T7%8f3|j@HKR~sD3NU|nwTV`=2cRMx)-tO25P`|9bn7Y{8r>rh?invFin@qI zKk_$=uReAd&0on{S? zFP1DLt*JG;xkWT;pJ2zeb7OJ9qKL5FW;M^Ew%6*vOkN*%uqM`C{O6=GXvv{^EGt0; z(}lX1KHIim;{F^R)z{Klt48g7t-<)`!_K3f!R%=SCfcXQqT_F6h-7T0phdWDJZpE3 zr)eac4(pe~A6RQW3@uyvr%%^n?^##68@@alO-M^42zJ@Rrr@Ul8lby5IIoZLtstnJp zPd1JW3L+nzc!^w&Z)OIvq87oh zs_xkKW%*>e0sGzk?d!+wc0;CH3v+Qj$D~2wA^c=g%TQwHlXajW#KJ)i%rtD4^ zht|FD%iZG_g*b+7<;Qd*+48tH4`+y@%7FuWkqSNTB3>Re8u2IQpff)GxYv#6oGi=< zxKhS-?i>h>A))kReP!I4J4s{W9|+Ah*rC$IPMu!zxvKqTvK#lA{!jQ00tEIdVwLJd zA=K?heq8fA`Cc@d!)-8t0FP{DkgfaCf5GQh-ARgqSaHnLpu9v;&Ex;clj>J3AnvIz6y>G14+(*!5HEVSo);n#>?k{=W(TEwh; z9)9g@r}5l-Uk=jq3SD*9_2WwtCx?9|m}H{q_+S485b#y#Dn7NTZVf5M>Y_wm^lnto z$5r^!5I45GW55&m&&rF8+(u~4hAZ7_eb-NjUNFpXYk$bBQ$#>Y9_ct|TA{Sp`8BXK zSiYQ4`_wv;XIS@mD6zlFt9WvD=}r<^PoFtEgD#k9G9uSW7Kfv%Io$(v6j!Ai@ysdL zjmqjMsY!TMV;yZOxc~5x)X(|P68)cs?eUdX*>NB11{Vc@3tj!Jy@0d0Vb5q(V}^zW z9t$hJ#y?t>kTWhf>W+IjC%Ht2f1r71Fg@h;+!O(3#hE(|5YPs*z)2W^vhMB|f3pLful;0eTLKbn<@`sR%BC0Y8X~RkI}YSn zq}AR1SvsEPUeHPC-Bz(D*Tok%@z_@AaJ%u_1rFNLM~N4hEo8+yWA4^pa2 zwXvKdo){$jo?#DdR$mLk`80Ig9TusDc)C8o@!(WG1QaL;^Bh@T`cr2S2xE|Cl0y=r z#MXEOhLpz9MoetFV!<1Uz0Nt!(4g_hl3AEPOw5@9Td#AmHaVz({ZGkOh{Bwsf3oqOSP z0xD*KL(83B-?KFJ?X!tC7dI%g$LubXj8Dc&{yTeJyKht`6P;ChV-D@VdCh1u!2mU6%2(6@Ax$#o9yO!4|hJo(B6!ZQ_)QZ+EWV>g4@<#VyrXQ z%$=4qk=Wm-^$XF5o%--X8m}t09QHEzS5sbO&r?8<4i8+sSjlYjsW5v5x=YnT*@RNs zjeXE?`vXKoMBi#=%aThalNGvSi(=47@a+Azza9nCIR^fd8~cl~;t<@t5|BWDBhoF} zhFB5NkZj$g4;o{l?5?hb!-x7nD;wZJ*JJEW?)R?C8iR4(>qB!HMsOj6p&1PkSRs$z0SJs;kvNe1j{A2I;HePA{#p@#g8NOa=Ktl zw7d`3)6Q+Y9jBu;S@Wd*Sl(do8?PY|K(hY6ltwd5vhg(k(p}8(wm%W}YIeTX+s$yJ9eg?G%AUxKM6!;G~NrPI>R?SCO))UG7;5oD@om+&L4W;)LY5l^io zY6I*Jt#NHE^y6d^`Ute>bm_Eqy51z7&BkDG(&#ZEh&VRLJTT>#oKjkDc-Y@!nxC{u zlAgoidW}9e0~8f4*oA8J;Z@0RCJ#(5E`_0>B=DpS){a(%aDdN zb(4nB*K_z0L6e9_X}n|bMWyO%w5CT#}}8 zb#NTWf{-pW+37+Y-DP#ayGP><6brYYrg{0Xl$RzY_6Ry4;Y1{YAxCSc^EJDXmOyI% zw%~X9$FQ0`y?FeDM{y6DeK0qH40Hs++$GQh$+ChyyNoDZ2*b?N&R>h;Os|4;CU|}C zyK43IUM`%Ktxsuohl1pY{r%41FSGZvy&N&}M%qWl7z0MdRJ}MRz9_~KqKH6g6$KIh ziSUx+;7Kzy_o=V-JyJ_pia76VR(?6VK4#cCPYT!h?2zCJ)r!oQft&4`sO31&Jc8w)_mK}8MGH7Oha66Xw76$N-GpVrdGr98N~ zUe3!jy$vT{+y@X28hDle;>Uls0F_0*FQ+ANj0Jt4A?rpH;UnTuH2>4MW-^#iPX58; zZ(v*iJ8)^hZ|1x4_8^CXnt~|RwiP7g>G!BqjK)`_B1lQ@&Gf~h`Sb4Gq_RyTa68>W z{SsWnr3xueY zP^JH#Sd%NF$5^11A#>?v#TD0__nLBzF zHi`0UYw)@}CF*5uVToz7-TQ|n`>MA|fg`aQd1&LC@v8K8zUlax$sv%BAp#6-6ihH1 z{BWbn5*gZfHh`ccnd&9Cq=iE39+pzgv!Zo&c!FViZjhmE`k1UbgU)!$uFG7S!D`u%@-MLvwi%YOn|IEMZuCmi_&9o&3=C7ru9 z-AQ+UTWx##)5$?;0Abihiz4;+;_P%hH{Z0ZRE`Q<;Gm(s;lvg<1mZT`x+^_33c~f@ zz!{95oSqv=yjV(!#00;6t8qQ6MrO(MW?fu(=WuX1T~TVra@bu0L?I?~exuQwPBr<1 zl&zM9VzjmO6##%Eg)Z@=me#Zqx-oY@@CT7Jd%lkh;bCt+k8y`PR4kgb-xnW&h9?Z< zs_i|ds&T>_q0M*9xy!VWI1>1#Oo_vSY1`2e;JOLbJ5|v#!0uY94^)KjFq$#AqHs4H zKh}B#-gaBKwkI{+|1P7A*6v@vf>|c@DePAg9hOk(^8mtTJ1kAreipE6Z$hPnaNRU^ zcl2XnD}P~rw$ZG-R%*KX4U#JPB2Ahys+}E^e6`uY8~BYvo(XP){KZTLziZex9chea zx6|WoMcj_~a_B@c1I@nC+)7kbem$Spmp@fFz!pM?_p$^GhK~JPeVI{D4`ybF_E$*Q z+UX+2qH*5m_j2;7^o9p7NqcCWF@|Lx=yOBnr7xO%@4%{0b-RZogTWUu@SfHiE-L8flJV%P}{HYAml)-TmHJIWJ?=p;XO} zm+kIt$|Lv9R<&`P(E|TBZmvrkH-DU#YeWF@`j&uFh$c@n($J4a?r&~ zwK74HJXRTwI)d7$kjgwoqelM~){Z2lIg*n0H*RY(5npu+yX)Az^rFgzA5r;D$bap~ zweBBqPa$vob8h&n2Zz1fbIA~=m@RpC*WyocQS>{wj^P^N{Yd}vR2rZaCj(TA_LbA| zdxRzaXqRR%jIl%}H8r-scjSnaEA9Vi`J1pp3^3^u!m|@i-SLWQo1Y^T0Z;G8?%`ge za)=h^CR#%%Nb|GjGq-0hmwtbsGM73VeHS-<8UuuUmwW13jI;6geil72d8GbUxTYMo zG*aMS@I$!3ZKcaBP&Z()!BZTANRQjU&JMT5n8IUy<|TwYg$T&31@WdjOIlHj3I_r_ zbyg66F3v%mtuGcGodwb+-#->SIq3}15IQj9K%5pW;@V%9H+#j?3|ZBB7uV5W52OIO zW9xNkci=w=cLjr;y2FcZSuUy=Hv3Xw; zSFGPXE?EZf_P}tnT-SfO+)yu8o@JjS{73-He`?Mwu4Tuz?kIiKTd;HZ46_{~^b^hpPH`geXHow!x6?r00x zW=S@8nk(7NC5WQ9odlaK8qllY8)T{4dpn4&^>GY7XXKpt65G=IN;hD?q-QYA2 zuAh*5xZQ{9pZ>mx z)xJol#`a%bGTjwkVyd*f-0uF`ZpaziBVO<%0e$;Y*^VZ|7l&pD+QGn;K;#pdyhBi$zCP}VM zsi=w~zKr1JR;G&cn3=^*&grott=i- zd2&y2cqUEN&Ea~>S|CZq%1JRn{A#@61k=XH^M_D`VKU4vHEcMSCk8(4vk}gvaKtWh z2Bg6C1tLr2BurA!>i*BXHr_cT5wBi7Rh9kD`Nw%;^fs%pI^Q|EunWX$!BdqJH()zmT^Q!?ngV@-DFQ~LOA zfyqGh^v=V@T3?nwLho?;%_y0T+VGSjHpIe-sOH3BYHcbSZl1sq)`xgpr#H^{$?2wg z#WAqUFz?O~gWVl=6?GNgkr2v`6Nkk8paqikfp0xBa&Tdn(sTJK;?JNfz0jxF%n&*> zyP-O%;;9(C)Lo9$-&BnrR6dp-xDbHyGd*4I#sF_(6&)F-Zj=wirM79L%E{juf9eK> zW*|PCY6#sh%G4EU#HEtH(*&qluWeA@aV$wpoF|ZUk9Pc!rv%HCl4^0uxq*}&>Bbu!%SilV{% zd3Uu+^MjaYwQI`kbW7bqR$yHCv=$AV#ZS%8<2dk*RK`J%!wUU%9JOcrofW9x9r()C0!MPT!feh9daXZZmg1Dh$C z&%rE);2yJEg>wqf@hA|}Vv*s|umgHVccdVCF9#A#dJi7tjUDcg10jIo!wNRO`a$H|b#BEz<*_;^>@%9^@ zJhN6B))bQY;dD1{;QJg8`T?Duhg}W1U$^5!0Zm+*s(u#WXz5& z2QF13)w#aUqu=QNv-R>f+V=`>+vBA&urM_6x@T$EA7>FiixNkJrZ6c zXq%ty3_z{x6V0&1!`qk53)afI@bBlI&Ir7=&4&%0SM?1BnqEE!(}T=Kx0D;a{*`>v zvN<;+R33e>!zqM1Pg5N(CU1R>vPBkoQ@Hxa{B zpAp+9!NLI|j1bFg7#WShgObK;ld$n--K$6LgN)zY&N<3JY3`0E4%0{~KfQc>;8E>GX9-{~OzY1^~Z4Fd`%WH;F+6#0wWa zWx0P75(j{i+wJ9*{>^xZ0o<-xn;rY#>_t1!P$SKvWM=+vsACpT^}a&VU9A7sBFzF$ z@xKTEPt^Z^Hm(pIO;;b?dw0P9%`yc;d4a)$_8(6n|2)bZ@Tlt%&bpQ?<{`cVjiTZ!W^*?v|AAtN1GXGAw&i{WGBtod*@1MMY45c7MjJ@77@x%0`ZZ7$m zRYKs#-1^|ePy2ya@!Y#cnwqhshgni@;3&VI#m|6PS_wK6Vm% z=hL3$#(f=T{8z|1=Afm66|4T)f$V-*@fU%XnSE+2<+B-349$b6=aphtFkI=5;(}&E_dPbi|{rWnhoTvwh zV+E!c=@$}eWI`guoT#(>yqxlivz&thGjmBbvVk7$2dJ)L!80L`_cTKz^o$`*q!j@D z5ANuZt9AvO2RJ9yd;aDhZhzbAsx_^i0j&|6Z#&CiACP+Ky19`6!BV>|Wyz&U>2SI( zlv70!xp-d`WQyZIhTwz%vqx%oubVu8VGv1=XVElRA;G3t&j@T&Wa2n*LP%ul6FX&b zIN#W)W(yBLSP#66qBf@>ah^_gvdbk7Aq41x4Je7Nigo`NXL8hv|C^OS-mP9@VXiI? zEl;ovYFgs^cE9xZB{EX*LtqaTas=I^QHbW!rgqk;)8X^39C?T?7Pkh}qw0MAi9lLU zd;la47~Kxm6O4a{51x?z9*+;>fF>wffhjq&^YqmkmoD1fB0(X|z=N0NGXp5dQW;B* z%6B(Y?z4n2Tf7T?4X#Z}Z!drNN;Hub35CW2LSmG)qJu!{PMxef;TR(}UsRzIg;^O* z24b{}PY`$j|6xu2^)v!8>YpOGTaFo5--*|41{$7bY2EMZ?L1^-#rp=77PQzErC70? zjn5kKaBkc{(L)>w5Ac*Y=W8uOxry=q+|HMK5mB173iP>rJrM9=a4kJg!VhUH3ij>~ zY7-s)SZ4unxI6i-DetdvHOp-lvsCXq84m@f)b>^Em0uCJYW>2%Fb49dKSi|5-Zd4vyFBhC*&|@ z3rgTL#iJpD@zAME%*B%d#@U-f;sJ`d7LfU8c-w`$7DyI&#(AM(fvPB~HSfWVh9l`h zF_w)$unE;UvLIPs;D8!Deyb=2N<0?)>sMoT+IQ@<3<)`vAoCa)Mk%lw-*Q~`FL>w@2nA3{A__h;%* zTkv0bP=G!2_1WXuo0d`Dup)9F$Hx}M=Yy2#MJeY5Atu1dmfvUfv4>E)>{3ehvfrM4 z_V(klIM7vp_N>WxvB(u0$}eXna4ueDQbG z^(_c!N#DxAUtPV;84~F!vOvb5cfFhi#KcjKs8(HYBdP>Ni*Z! zhI2s8wj}&q!r-1v5y1LCQ)-QFbM_lOT{72O(cQfhvRR4P6Iij9(~AtaHT<6~Lk;}E zXcBPS2GaZs4@Ouy>8*;*2iD#c5?=u7>yGgM;?Z*XoidDHHY@^qYbW<>s^1%th}_k( z{bB9_oU-pbM?o+`EXCOd$s~#a7RAc+uQKiS6{05x-OqR zLO>dT;W4u9+fsH&0Y(D#=k83QN6qT`^ZW-4vS-^zf$%k80!a~ zUNUy=F~!`odVXG-Gf3P$Kq8}B@mj24O_y2bNmcb`lo+_(6R%kv3UscFPb8!u7HKOp25g7jbc721-Hy%$J&K9P#-Ed+VK&d`ErDmdLW_FDO#4E1#l1#Iu5j8IgR4bi;C%vFxZ@Ck~u#;gmHmd=cA_=J$ z8zcogXnCUet~CV_FhA=G%AqBD9D>O8r}}-)q&B}S|`&+P@UVqk(^0Mg*)J^^G`Omd9(s5~5)Dkewh6euTDx1*i^ z3;@6b0&@YwD5B;BYP8(H@aaL^axby+=jgW22B%;zrIhi&`ru0H?BYWG={iftTi^j+ z^umSGG2<(NZ|~Bp#hhtI=`uj#$S^ic(7V$$w0Rnp@_=Nuo|f8ctrni)q~BneLT0g+MZC6nn*7Wc z#jp|qSHBO;rzat(SL=q)4K4Sn!L;OY#J4C`h7_<#B~YfmomJ7_IllMrY=R_H27AR#B23@@cJL*-JZYd_=eV`u}3~%hOw)wqhtg@8FWl0_Z6~{mlK;Ts8{%|u! z#<(U@2PmLX3>tnhj{UjfhlX}6hJ;#67SllLFU$eSYV$XrN^s+6+vB;d8Js^C?@1yG zS*Yu$P;b*=yDi(pz$0%-_&g(l3r73RY1mxf1Bj$i$OE&KJy^cOakEm6!xoH?1Jq~X z=$!z3w`1-v?9t!W8@@bE{R_a+jn*MzF6gm=^2}@#BL?>zsweEfHdJQxjuZ58ZHF9G zTF!IQ@01UC4SOwN|FWd`T7mWajeV>=fXR;9rlE0%Rtkk_`IAl zy}fIYKL35D4>l{51lo4D?D;eR>|{(nukxr})RH>kO~%zTg7TD#IX>>cmXEK@k8{2# z>$!#@^5<;qf#JrR?u62kVhyLMk{5TDBXypFkqr~_xf^b20{(x>^Au7TC5KXL!$}w+ zt%9rPb&b_AE1PBt`dzP1PFC+#(6WZV=Zy$fd--ML=UrZc>p#}2>UOGT#JBH)J@d_f zif%hpH{-iXAnIqz41CWOkQ8uZV-jaBI00Sl*Uk#I@%Z`c$x}FC6KZQkYO^BfgkREE zT>>N4MG_*>RFyul$VT(F4Cr2G^HcGka_q+nw5-ZcpxcD8iTW#k;?PTpo-C#Hb}fJ& z1e>}=H#W7`@zeZ5>n=Tu$_K|^1CAGR>r(Q+8feYK1=^K%`>^3&-GN7J<2&tj5J@Gs8Yq^WvBJbgB@I07)AL>b8I3u65&K|KYje(eGT{ z`D!YsDZbOw^D1qXQtrHA`0jVxnv|H&=yPf7b!?yX>VPYzNj)l7VzD~zuSLs&88eF= zrVM5h4VBTAA7Ijd)&O!61MKPni|+oGp=|9BM{tr@ZgS9~IaT>!-e+?(>d4~DWx(%-vQuL(X*ez~;6(6Mvven^Cw^sGH-KwPl@C+RQUo{VxWaJ{7#K zi>60^$U?QmJyt9BEW zQXqXU7yeoh%eEK=I_bkA@TsL(PDE_O!OR?3F5zsy6@Go z@R6>d1o`5|e-qRAQ%5c<&fOmTI2ZI;^WOIT8XI@?*H{4o6Ot4xE(TLFHNTb@3yo^^ z@!!&ckT^YRys0C5dzYI4rL~Tpw9g^Y#^M$AL{rj5P1BoBt%vXB#h0hhmeMm;*FsOC zsq1(wu9s_D!ZsH+iHra`V0z-Wr+Uo~yeoS9A-0zXve%EV@OgYtgRA`J+WG~y(iVMEf7J8tH7h9WS6v1W??iRv1?32{@(cC@x<h1V)9Ct+r`z}*6Z@yijALJ+T=x8?hD97TuD`sYuIhZ25bN$Y&;kl39C&gK+mZ-o(MLuI0T`ZpW!xl+v#*^1|8%lABRy z82k}UGKX9Gfn{zwQb4@!_%swg>f7;Kt=s37`WVG$gwqTeEn89Igmh~)2 zYo+OHY9FNeT|cCQT86YN_cM+&Cb-l(_P&i#cEFVjpZEJSVo3=K1MSG!nirfJ&X`Ig z_~*aE#ptG2+{tc_DA()RbH1@QZbh@@T4)yE`CalEl@B_+bWBwN9puwKY<3J*QnZ_m z4oF6+!^Qsmd0&SPKQS10do=C&OZq~*kqCP!TnIR0r`A-$aEck;Js6>N?qjyEb7@Tv zg-xh1T4ih#k6J*7J1`p<^M^a(qH0W2Zx+%41|;4nhf6LQ+B&gxj z6%0RVp6rc?zqj~&j2`H>uN?I*h<;s54K!h;+wx^K&5{PE(24$l-gRK~AF*=3O1^k# zP7sZ?VhN%LktE$SU~82BxlZq=`H%%YR=YGrhf~%^L&lp<&^W|XwNA90Vn?O3x)qT& zw`-WZ0CZF3A32P=f)-!sxo^JgajECYOnlpOOIE1#_|!dmgBs-%iWKfCKGL{sGv`yf zCz`ZBXd*N42seAN0;~7t=EBrk$1?80$GM>73qIwvl}FP_dImoVfYU&vlgA4loR~Gr z>nE~h1l#&IbJ3UVedzNiXi4!T_tM zxYZ82kY_-j=bK##599NmO)8@B$`7iFXQq#K-V`!RXj9(O$u}NclWUolV$~0h*}Ig> z{a+c~Q)bs#>e{2V4ipIfzv#l0S|89zcIxRBMeXf5zx?t|q6UJejXyR0tj00_>1%4h z=IXQA)oJbFJ6Z|ht!q#7i9Xs8=YiHgFP>mU&yj>@+W@B z#~@A9c~_q&#=0<1|GM+1s*ajykj`z;xkiLPHkiF>lIYN!^Z)RL{>n~d={sehfNQ=w zz;pwGX8m?vD|>`TT6nJ}Wg!e9pYKP}nWTFO&b~&R{n6{Owl(XWlCJa|6p66tYTN-q?@X5nB6+ zU*+m;VB^`TYPN2L$xNtc^uf8GQ8`3nYJL3LqUihifAV>yW^A3#@q7>K+s)Tu{Vd&cK^LU3C6=48f)W=sjPW=%$Og zPXea3-CM2}W0;17=fY*8+16=PrWWk=36r@jli#U1eQeJk{@L=2a@io?FNcJo)4bjw zX*_ZA{-hcGS(4XP^!L&Y!Gs{fEgZ5FMN8zuZ+aT(?qV5n6|<1*!CDmK_RgZ|_0OT* zR(*_PCRiYHZqgXlun`5 zU$@HoowST$PN><{%z@3pJ=!U;14Z#-$rqMOOR9(RF#3fPYeW4S`Y60mli2x;kX@I# z>9t`-WX$cJn&VF`WL+3#Svhkyg+--BRu&?mKih`kRe3P)e$v5WP$Uw@#-cg%Y&Y^C zOtQgwnB($1?7q=W9pn0J)4~kzURb|B9|DAMJmB4R>C}NG7xr5zefd+(h;{B+dn_s~ zp%Nsux&eWbfMg`U6$>=@26Qn4Ojd4|c0I`bLV@XYfWL|z0fHD;GP<0l7@v7q9RHa{ zX2^(drhhY8`K_)u-p8bN|I>Kpvai?z-}66AkEI%qvAdHsXO z#Um(6;E+ht6Q_|9c3_VpV0t3vH34W!X(u9U?nj6a$agd=!R%o9p8502YXyDm?!!K{ z!5adr6X85VdvmMn-X>0(i!oXA&>)+fFZh@9=V^vsmm`_D9K?OkDWQWmS9N3?xiZfCm)eCg21s3s zyexmBxxO3nE;`X6R7aDA8b#l@aYn5;ghkz^XpKU_sH?}8U z=9ByL?KfqHx5n49K1gtMorcmhsR)t1X+6$g^)A9~JadsAx+d`9xC>a!m_wy*l&U91O3UvY(Uj?Q-&#pTOF`E@QD^7>Mo)d~JlzphzV4{+* znm&9nRM&AcPi}zsI&w6nUl6n(CViA~gwPsJg?fN&iwUSujIy(^Vi1umNCxFr&$s0te=6s{YVqL`1P;` zawiLg`_NxP%y{7GidxI_s_`Yo^2LWEEs(AxxnP-ty*bX~Gx0a!GlBLqlAq7lq5@vt zn!t)?bLJ$SkN!Ls;QIXRDb7R9>@T_W^r=?JUSXJiIoO)7_uD;>*2H_2ikj%X!cD#a zqt-vL61oR|)C>d+z*XVUX69qj=v+GwCM&}HBO;fjCj7I3NY4r2eKfjDhbQ`%^Uo3z z1j?CYHhd)yM?r21Mpw~AAiq=e;`Tvio#~$IX?)Dz^AzvDd;6xr7{Pm7 zO63@onr=vQKdYP8=fIt8#=C>k_ZVC3o)s4ZE6j*gG%B)l_mKwtre6ur??8Idn;LV(&DMY>xgn&klF+ z%~H9*mH!SEjQ`5oiNL&3ML}{5b!|UIVqZ-(yWIl#*C@yWISR~hje zrHtwg;Dbs(`BkrlGy^iT6fn#7#tn|U@XTb#3v2jZzLhJR*iGBjJaY>)nx78a5}vuc zccz87nsX%y6?tJ8DUvg$Y%BGHbDo}FwsJIUMK`M{=xL7w06)2ALDIIbd-mLp!o;d- z!_q%zI;)-?5f!lH4C*eD5d(g*(4F9_@LGv{?6HWsgc;9?_MS_gM3G12-L-F(t=v22 zn_o1quO_>D`A;fKq|irvSI?$ccq(U|^vo}G+H6B+L+tB0aX_?Szk|~)>Y_ZY!24Z( zWa)fYN_rThZ3l;(*9}RVlfFQ~SCtS%KB&00QuX!fGCmo%mVTa<-+Xyys&IGhvL}W5 zjLF00>nkotz!EDJwg$paqTR02{D`A>T`wCc16@b!bY|QROV)Po_ZW&)jpR__{)_iHxv}G&{;6MD&y0+)?u5oNd{Iaj`i$HS9 zid8!npdsEEwC1(V?h{bSo{zH2jRik_xwZEGT#t_XB-cvf6{ zIr4VSTqO7Vow!t#BFo`uiM#ov`wWYxIf2aLVTa6=Y()j$ev(gh)iNkC~)VU3*2Gs0Low{%JQN{ow!Nj(Hrs(pdm@ z9r*Fgt{^hRwCs$D$Co05)_*}j4SFOFoA?-98*SIXo=p;Wwdt{}q@H1%uI4MrFm<;( zyVmz`E+HcKno-RBJj`&`E_jQ>L94C<1o@VxTpfi0h5oLxLF3ygV)VzP_mAjj@?@GU zt#atjj=Osn&u#g6X)TXL+`48z-5)E3aB!+RS%Ko%pHV;T1tGAXJ`90!fFl#~+}&;GHa68BCY<`8 zMCO~xwtlx0gI%{MocY2y9n<>GKfkf_9t33@-GgO0By=6ZZ|o3FEnBJwjVoPwhRVi! zUPY&`$EvngrpjA(He{Gu{T!-#$^0ity;jqpdsf=ltkW+y}tzFG^OC*e@)nIMP$*8uzsii z{vjh`0nFX?RkBV@s(T-}u@REp&{UcwTU>>m__N!N{RUJN=EK+62WH1mWpP42anoxWLK=W#+)Gy|uxuqI-2+ z#{;L%{F67b@Gs87dHk}YBq;rICGnMw2?0OThcLlr-S4lv^}U&M@5HIwnb&1>mp*s@ zr09CfMa9HE^HR=F+e}u6BVjGqJMYZWoViQSV2-5{1n4)8`zH_!dv%k6amC-02KfR( zfwMjUfndS8M%iLtN8-D`@74&e5~-*U#1 zW%aNgNa$mqUvzrw_%=9}r;WDg-5F!ICIp+Xp4dK-fZehJ^;uZ^iYkJ6jtf|jZJ(p% zeq0gQ)s;}L^3w||7VnqCSuk#PU^%%07`eBQ~#)6)!Y z1U357ZgQ`GnTX-ek?sAIR=daRTmBhxyC_4yxxqjpsdh88zCL5UXLKl*!2r<2tg|eYHNLWDuMJ+&p_R|nhP*Aa?*^t= z4T+Ea>b35laT|RP zE|;174^a%5je{WP9#Ki7s~P@!L98tSuDUJ$`eoCsuJE`*kKx zv7B?)!|4-&bEKaO0WGL`g7q%iZ@Vajp8iQ3SD?l5QuMk&b2BPF>L$0R02f2is=>WF zUuLYX{;&}l*yy?v#S@R5c_-2xI2$47?8RDTy#>(j)U}Nk301}kHCzdgNMv#2_F$|? z4!UyBrn3rdW6~l%lv^;)hVD+-GaOv)q1Mb6`4hRjmbJUL^Q)BhK}ww&1Ob`{$5mW= z>`c4qVSqpLqSDr%P_(qHntSvaSN^I&!hZrp(zD^>P{B6o)>}^<4DY8*=8J>lG2Y%F8Zu+)*v;?i5(yj?>`M)o%SP;cIC_7r%(ctXQsrlz6bqM6E-k==Fnt zncQ+qthvbBP-~F;7m{d^o=M-?_?pe-W+e^haa@pupfsM3&4l)#b+ffnZ2P>{>PKrnRQFaD^pTa z1&pBOW$JFu6qn;ySpy%a<^)GBlFMcA*Mn|4zSzp_WXv?)=Ic({S+#Yi9G+PqJ4Km| zVvOL+=u2a3Ki^h#mpA>(6C#-Ki|xanPinKXMQ6l&db|woV_m$*M+O(Rm-%n~b2VBY zw8HY!7f~2wfZXGr+DsCne5d~qJBf?i-9f%T<0OtA_G|EXx@XWVSyeY({BACH^`-slbY%sy(CVaCW9mna$SmtJ(NOo( zEL~*6t9BVCs8PzIc+z-(j3`p7PKNd77JIfPzlC(=YB%VW zpE-7_tP>mN%<@y43;&s}lQF)n`fY*Uky)2ajNmhXa4k_Q7Wd|j3h;ymmk4t{+@+_P zm|aCVY3)6`$akrNDFVSoLp5`|Ok(T0yQ>ie4*WK=LGz zC_USys~h3ptmyA8_N5y7+GujC>pg2hAmA_un;ju#{?4ICnuD#gw*e}93rWm3qiq#e z%zu?G8~8a7Y!}fFLLja`>`j`z_YgOhNH6pxj)r9}pyJ^ZGEK8*NVqlN$Op{l-CxRO{2orDk;p_9xnctDJwI)%m~* z5X4~@!iiH>b)!ztPd+m)Cl~eJ951R$^#MDvaCWBnI3wA}nU&C(Y8`078!c~hXq#a& z{qkk{r$!%-mjcHN`jK*x64dj%Db2>ofABrH>N>pcn_LuK`7Bn#r<&n~Njw-89}@uq z<*HE*P|u2*5P|A>hiaBLkm!3%Wf5kTd#Ud(OQhdb!Eg=hb~LYwKEwPjPd;Fn(yTYK zmEnRWyd8Niir@!=#=(T?8FNoxPe1L*VB5l6%FdzZ(zmrQXUg(>p_q+6cO;Pp4Mkzj zRQj|`NF4%ks6srBV6!ncsUx#hAy3Nl0&KVV> zvu8Wmqj25?gcIQlGwdBT{>3wM7f^b>U2t8V>|natcxI?IkNfDY+A$6NV5{hvV*L$S zo2(8X@PBkDqc1IV3G=dZF_QM@4Qx(&3s9RMF(u~{Dy>?rF&NPMzsDODWWD+Yi$JB> zzi~SwIQ(G!aOcgeQ$~{hZP_#flII-KH5?a;nE`WOO~05Jr1nA}>Q2(#JIT}uHw=?` z7aC@ac7P384w&&w2BCdCs~|F*>P8yIE8h}wobSz}ieO@V$h(b5IOhMwxV$q%?2^o` zE>jIg9YFK-tvU|Wd$qAPKx?z0Uk)M7XLYL6BeJPB$+UplDG zek&qc*`8|~(+^HhzNqqQ+h$~-S(k{cZ#R?%rB3|5nlduaF_PK|0Tv>O3$2aP7yGa< zpZZwmIOMy(nTa12b>99Tp3sTT%T$PIr64|P0blrigK^KjYrJ~4n|O* zT7sM#EN2`(B=8+q0#2xqU$c^ZnS58-=u2Z%`pwGPaBgtza8mq)%Sn)EHLIwnd#+jF zadywTC2XA=kuuS|q)IcVpHem4Wt=||nwzDuK6e=9GyV)%sx!ZK1!0zM*hW~0&4P-s zR!EcOd}?~phr@bv?l>FH4Q&l@=^vn~t~wfJcyeA}%x(l=;sswFF|Xr>t(1Mmt&|e{ z3x}LHWvk=ef+J6@Eq%JQhq>`=@ULmKZqmO*hOFrBB|p0aP1 z_GH^UOYqlEGhh>^t7bu7D;7l{^<{G=8n|d@R)?0e(Jre0^(TnyiJ~7U?yEC(z?#aQ zCf;bVg_i|oU({hCZbJ*f;>cIi^r*}w+*3S3PzC3Ny22$;#MHxxx4CDBK5<{e+e>+Z z`uX8WBs)y~d|NiM`d}(AV(?+m-ilcHAe|foIzmwM^0ptWNtXW3-Sj zG}vRr4>UhfIc}u+P*O=X7z6s;#IE&x>=AEPkw`H~^xxd**Og-q`Xt8tanrhH5uDPG zwBoA-zx~$N!q$$OiGCnAiftM=0TiCa)cd?CS?%HSCqTp#_kT8hsjLkfsk=Y8NgJF)m6 zvEIJcnO6iEKIuS+A0mv7k!@{(QS;a<{VmDeNd3HGhk42x2Q61qR>9W1RRoA%&v?+? z0-@)P=gTnYNyJcR1mk>p3o`3YO3bX~yEF_aP35vS-CnvNq6erlhVG-oePC5g8RJ`- z#xDKaa~qwFcSr|&Q`XKHJcE{z6UsBHd4h~p&ZOB_=kq!A8-MZqXVxOn$Pi5S0D8@DgdsC(isA>l7 zu4GD7Rm~Fs>@Mhol+(hoSqA%H4sAStluS^+mS#*whPp{Mke@w#wZuwR2Slut^ivcGYc)C<>81H^!Kd_5e z13?7e1w;bEbL|yEN0qhnis-jbtT$S%SvEyn)9uk88Xl&ios*6AOaku} zmp^4@NPF7aFWgeNOcUSPkwL;;yJba;OT;(L_s@5KD{FhVR)@;otocvH>;R^Hv;P^8k80z2{*iC*R5rcMX=a+~?xq(q z)fW&&UvFVC*Ztx1lmz_YsmIDQbySC@-38|kfqTro z zCn)b8&=oMu6ygwwJfdasJX|@L6?m1Dv0X9t>JAWO^UIj0#&(3UrHx;vP^3g= zL{(XT!?`D*pP8)WoGHYEZZc$!odTzb8n)q0|88*>6P z`?6&CSv_W7r2yF0beQ2*?V^_%pKktVAo`)T^26X@NpK_*-ni{D7{Sp{C0A<|16l(; zOL*xGW|*sKsiwHvE!h3QXe@^a#6W3}8!DQu-h?A_4gkeRYkt4NC~GR5P8eyp;9kVQ8$QG$5ad7Fo23Z~ak1jY~RXG{v?3G$RarFe`XePu3X{R+=mBOw&X zks)|Sc$RcG-jhn!`~-x|vg!&DA&@}QH^RNdyy9nq56yrU$^qAaS+F_NOaeFb)CVaH z?!UvPajgrK&zqdAs>&Def#wkcG_UhmYOVw^M`VZz@+4IWAVzK%`+za9rm2SD9={u@ zlx5D6UDL;lc7#9`+%vnlP3PescU=N`DHQPt_N55GNBMkVCRMR4?fvp zAFsvcHN4c9rb>J@{*IH>RTr9de%9i4Gd(cbFa9SP4anhoP;TA0!oZyB8?lNMDHPHK zCaOaFU9?x2A!o>p>mCF9r+hKs9Czu_P1l$LWU%}q#)=T3p`ZnYyeHmsewqw`}L^4LuHqfo+CG6<2n7#l^3;H^^!1 zsaieYFnN)Kc7Mv}^xE)4kXUw8<9I+jMB@QV9T9I8haLDt1Ne#exWUfGYG$4uMoEu& zo81#2up18Y40h%tIsOZglp(ltVsE*j1~$lVd|;rN)&${~o~-%KZnJp&3|OFR{^8E9 zJ;fCu53Ysw%}@VYWE*z7r)&4P=^B-SF%a@>*9g84<4aFUZT7x)qdsS+#2tu5NbpU@ zg;EwV)l-#sK>#r9>(0Figx{9lKm>KvRj;y<8 zc8SxMW4<11(s@QMV_}n9MRzA*62->vzxmHh1)GVASEJY7LVtRw`Rv{v`(Fuc00(&o z%m>gS2aJekmdNQ4p<{pD3HqZ-%4hdU1__xYhLi9mTJXD|E zE`t6SX)}l_DY5vO0Xrs#O6_DKtPKn0f+e~SprDYmJL_`<053iA5P`zn z4<5etc%aF58sHFr#M;U-9|=;l)J#Q2vS!Q9(d(EX6fubL%uA_lqa2%!cpNIv78QZ}Ayo(>C(ZpsRtKhzD--fpuoCch87cX-Bna9_{z%$b*dHM0?+T&Hk!+^UM`r|vq z2Id$??bX^|tfYaE+h#Nik(ZcN+wt)28q^gWe!y8jDCXrD<2qV#49x@5$8&Zrd5NTs zNYcix;9fe#PQQ;T?!6hG>9K{K+RCPqiGc9z%t{=`QaX>7O{l(+#7mJ1>Rae^J?82e z6cLqLypskTCyu>uc~$0-XZ^1Qvhwr+pKQ#CKImhGu*MGM*ZrROuAHWuT*yM$ieEy8*KLFMMdLZL|D+yDmy@3_PELTEVMI6nwfcYA3ZQ9wwKdtkT z;`;z7fU{U6>CS7kr3=A-()_G*G(Mjf2wXKe

Fpy)y!S(AQHSG#udd_8#b4sQu!R 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 PgFh2POM|ilu9yD@)d*=D literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon120.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon120.png new file mode 100644 index 0000000000000000000000000000000000000000..9c60a1761dbf62cc2a45ff98b9fdb63ade16e4d9 GIT binary patch literal 3773 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 Dh-f%Y literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon152.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon152.png new file mode 100644 index 0000000000000000000000000000000000000000..448d6efb577d07e227a5c62545173ddf6bd86b55 GIT binary patch literal 4750 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 literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon167.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon167.png new file mode 100644 index 0000000000000000000000000000000000000000..8524768f8d764da7e9c452a444208708f2d18ff1 GIT binary patch literal 4692 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 literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon180.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon180.png new file mode 100644 index 0000000000000000000000000000000000000000..60a64703c0f11d08705cd607f7751338707f5919 GIT binary patch literal 5192 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 nB>N_)Q7iwV%v7MwAoJ}E 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 T3-0p800000NkvXXu0mjfSlal| literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon58.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon58.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad04f004b638bf781012290d78e4138f97bbe5e GIT binary patch literal 1761 zcmV<71|Io|P)4P%ubY|S^%$zf~ zmwTOa@12BA$oV-Y9!V&U%c=j==#_}M2ylE}1m>yyDoGsZ#Yy zNX}RO*f(MzmKS&u`qiajIyW{Y_LC%m2NqT@Ic|QpvYqwNgBK7n5X%c(3k^?2>EOA` zqGaXjE7H9BiJ55fh0iJRW}@=&(@R^E1hLB>kE%PS6eP@VZVdtn(fh;5DPKg!j;fJZ%)wH{Wn#~V&#n(o1URS zsyS`0Tu2m;-H}z9O^h`!UZAFr@?0a7Z;pYOi0uZhgzh=rOEDi`FIkKtVu*gEcSM!h zmb#_XR$akjlg$JI75MXgWkG7IUnYJ+X=1J!qJ%jXVj{L1I2QU%?=?DgV^U?)92DZm zV?>``xT1#kZdgUt!2n?|0>*6ae4tikA9FAlJ}kjmMQm_z3LB5sZYHBKdbex9_Hv@K z%Y?q@9-)b7vJ6X$3h0B4tH__=#*`9^efY@IQfghn*=E2Nb8sR8lrQlu`Ca_Rmm6>Z z7bkEe^w8M>x;hoNUvWu_GZJPVpI;bMTsBpf(@U$Ch(-gk0T#WpsaB1{7ISQ~Y48mW z;Nk?@LjM_?q{BV-D=veoOmJoncVDC1GwGGz(O5@o7ZkGCIJMPO(7K9b6M_wF?Xqd< zo4J6KF0_U2<1=T3x0qc6G6#g+^=N{QTpChC!GZuCY*|eU{Rw)LMN7a2wwbaCdn_dE zzy+Lip(XU4-+SoTFyEcnH3?HRV^%-;Ylx;|>8v&^Dy459ZJ_1zio`68!6s8SO(6sq zaN75WUKiF9+8MruR3=w5)hzA^Z1clVBuXc)+8@e);xX7bfygR&FsIIt-gQ+==(c;S z#J*CO1qZBF&M&6TRmskZXaMOU6&?jn_(BqY5 z>Y|^?uOh;yp6w0QR1`>tiEz_-{Zu!N#(nhRndJV$7;LOgPyZQ*J2yCin+~*u!qKj# zItsG2IDi{ZH+E6j=D|ht=qWxKNxaA6E>3Wna>=z1gy?*#>|g_1^BGspGro&OWRc(k zPP)(*y0WZ7Z-kICr3#g7($P*LCjE>7S`Xh~s!b~bPTo0XSkRm2T(M`QZbv-`Imx*Ulqk*aI* zaqa*=>61?nFb8w3wuiA&zyVyGz>!cm-pY3xEsMEiY)Th4FVrtqWp%V~gxW82)>4^N z*H{>GR?m$^s6BN^M=4^iEjT7(gM(8z7K#9Sn(M_`)oSH2zHDCla&cmK)bb|4nAMIO ze4S3gI9L8AD+T9c#C8K8JF)I68NBWK`5pE`q^OR#h~-u!e7P2i$UDq7^*uZr< zbp8sR<$nYxb8EKH|BltapZ^j3+PZt_u^PR*lT6;TCNxu^yFH$j(!JXvbmHfQ>a0>O z+2k{tOWD%ln$M`tD&>+*KBKvmEgi1;jOwgXF4_DG_&r&PcxYTT00000NkvXXu0mjf DptxI> literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon60.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon60.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd52620a8f15577e56ec7fe8e671988dd17ab0f GIT binary patch literal 2537 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 literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon76.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon76.png new file mode 100644 index 0000000000000000000000000000000000000000..b058cae2f440e5a5875e45c036c99f1fb6356046 GIT binary patch literal 2332 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 Kc&(xHv;P1B$EH01 literal 0 HcmV?d00001 diff --git a/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon87.png b/samples/Firebase/AppCheck/AppCheckSample/Assets.xcassets/AppIcon.appiconset/Icon87.png new file mode 100644 index 0000000000000000000000000000000000000000..4954a4bd33f613d45f74dc0b12beb516e3b38661 GIT binary patch literal 2758 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 z + + + + + diff --git a/samples/Firebase/AppCheck/AppCheckSample/Info.plist b/samples/Firebase/AppCheck/AppCheckSample/Info.plist new file mode 100644 index 000000000..b3c854650 --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/Info.plist @@ -0,0 +1,42 @@ + + + + + CFBundleDisplayName + AppCheckSample + CFBundleIdentifier + com.xamarin.firebase.ios.appchecksample + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + + diff --git a/samples/Firebase/AppCheck/AppCheckSample/LaunchScreen.storyboard b/samples/Firebase/AppCheck/AppCheckSample/LaunchScreen.storyboard new file mode 100644 index 000000000..780b7ed49 --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/LaunchScreen.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/Firebase/AppCheck/AppCheckSample/Main.cs b/samples/Firebase/AppCheck/AppCheckSample/Main.cs new file mode 100644 index 000000000..5241af3eb --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/Main.cs @@ -0,0 +1,6 @@ +using AppCheckSample; + +// This is the main entry point of the application. +// If you want to use a different Application Delegate class from "AppDelegate" +// you can specify it here. +UIApplication.Main (args, null, typeof (AppDelegate)); diff --git a/samples/Firebase/AppCheck/AppCheckSample/Resources/LaunchScreen.xib b/samples/Firebase/AppCheck/AppCheckSample/Resources/LaunchScreen.xib new file mode 100644 index 000000000..c13103dcf --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/Resources/LaunchScreen.xib @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs b/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs new file mode 100644 index 000000000..1697899e5 --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs @@ -0,0 +1,54 @@ +namespace AppCheckSample; + +[Register ("SceneDelegate")] +public class SceneDelegate : UIResponder, IUIWindowSceneDelegate { + + [Export ("window")] + public UIWindow? Window { get; set; } + + [Export ("scene:willConnectToSession:options:")] + public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions) + { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead). + } + + [Export ("sceneDidDisconnect:")] + public void DidDisconnect (UIScene scene) + { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see UIApplicationDelegate `DidDiscardSceneSessions` instead). + } + + [Export ("sceneDidBecomeActive:")] + public void DidBecomeActive (UIScene scene) + { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + [Export ("sceneWillResignActive:")] + public void WillResignActive (UIScene scene) + { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + [Export ("sceneWillEnterForeground:")] + public void WillEnterForeground (UIScene scene) + { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + [Export ("sceneDidEnterBackground:")] + public void DidEnterBackground (UIScene scene) + { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } +} From 188ac67fb968684ba6d6fed506dace311078db72 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 10:47:56 +0100 Subject: [PATCH 16/30] docs: update BUILDING.md to include GitHub Packages feed configuration for fork contributors --- docs/BUILDING.md | 40 +++++++++ scripts/configure-github-feed.sh | 139 +++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100755 scripts/configure-github-feed.sh diff --git a/docs/BUILDING.md b/docs/BUILDING.md index e6012cce7..41632cfa6 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -14,6 +14,26 @@ Restore the local Cake tool (any version `< 1.0` should work): dotnet tool restore ``` +## Configure GitHub Packages feed (for fork contributors) + +If you are working on a fork of this repository and want to resolve NuGet packages published from your fork, run: + +```sh +# Using GitHub CLI (recommended) +./scripts/configure-github-feed.sh --gh + +# Or using a personal access token +export GITHUB_PACKAGES_PAT="your_github_pat_here" +./scripts/configure-github-feed.sh +``` + +This script: +- Auto-detects your fork owner from the git remote URL +- Configures a GitHub Packages feed (`github-`) +- Allows `dotnet restore` to resolve packages published from your fork + +**Note**: Your GitHub Personal Access Token must have the `read:packages` scope. See [GitHub docs](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) for token creation. + ## Build + pack a component Build and produce `.nupkg` files into `./output`: @@ -58,3 +78,23 @@ Some packages (like `SignIn`) depend on `AppCheckCore` which is built from this ### Code signing errors during xcframework build The Cake scripts disable code signing by default (`CODE_SIGNING_ALLOWED=NO`) for CI compatibility. If you need signed frameworks, override the build settings in `common.cake`. + +### NuGet feed issues + +If you see errors like: +``` +NU1101: Unable to find package AdamE.Firebase.iOS.AppCheck [...] +``` + +This may occur if your GitHub Packages feed is not configured. See "[Configure GitHub Packages feed](#configure-github-packages-feed-for-fork-contributors)" above. + +Verify your feed configuration: +```sh +dotnet nuget list source +``` + +Clear the NuGet cache if needed: +```sh +dotnet nuget locals all --clear +dotnet restore +``` diff --git a/scripts/configure-github-feed.sh b/scripts/configure-github-feed.sh new file mode 100755 index 000000000..22d52b0e6 --- /dev/null +++ b/scripts/configure-github-feed.sh @@ -0,0 +1,139 @@ +#!/bin/bash +set -e + +# Script to configure GitHub Packages feed for private NuGet packages. +# +# This script auto-detects the fork owner from the git remote URL and adds +# the corresponding GitHub Packages feed, allowing contributors to resolve +# packages published from their fork. +# +# Usage: +# ./scripts/configure-github-feed.sh [--gh] +# +# Options: +# --gh Use GitHub CLI (gh) to retrieve the authentication token +# (requires: gh auth with read:packages scope) +# If not specified, uses GITHUB_PACKAGES_PAT environment variable +# +# Example: +# export GITHUB_PACKAGES_PAT="your_github_pat" +# ./scripts/configure-github-feed.sh +# +# Or: +# ./scripts/configure-github-feed.sh --gh + +use_gh_token=false +if [ "${1:-}" = "--gh" ]; then + use_gh_token=true +fi + +# Auto-detect fork owner from git remote URL +detect_fork_owner() { + local remote_url + remote_url="$(git config --get remote.origin.url)" + + if [ -z "$remote_url" ]; then + echo "ERROR: Unable to determine git remote URL (not a git repository?)" >&2 + exit 1 + fi + + # Extract owner from URL: github.com/Owner/repo.git or github.com:Owner/repo.git + local owner + owner="$(echo "$remote_url" | sed -E 's|.*[:/]([^/]+)/[^/]+\.git$|\1|')" + + if [ -z "$owner" ] || [ "$owner" = "$remote_url" ]; then + echo "ERROR: Unable to extract owner from git remote URL: $remote_url" >&2 + exit 1 + fi + + echo "$owner" +} + +# Verify GitHub token has required scope +assert_gh_packages_scope() { + local headers + headers="$(gh api -i /user 2>/dev/null || true)" + if [ -z "$headers" ]; then + return 0 + fi + + local scopes + scopes="$(echo "$headers" | tr -d '\r' | awk -F': ' 'tolower($1)=="x-oauth-scopes"{print $2}' | head -n 1)" + if [ -z "$scopes" ]; then + return 0 + fi + + case ",$scopes," in + *,read:packages,*|*,write:packages,*) + return 0 + ;; + esac + + echo "ERROR: GitHub token is missing required scope: read:packages" >&2 + echo "Fix:" >&2 + echo " gh auth refresh -h github.com -s read:packages" >&2 + echo "Then rerun:" >&2 + echo " ./scripts/configure-github-feed.sh --gh" >&2 + exit 1 +} + +# Main +FORK_OWNER="$(detect_fork_owner)" +echo "Detected fork owner: $FORK_OWNER" + +FEED_NAME="github-$(echo "$FORK_OWNER" | tr '[:upper:]' '[:lower:]')" # Convert to lowercase +FEED_URL="https://nuget.pkg.github.com/${FORK_OWNER}/index.json" + +if [ "$use_gh_token" = true ]; then + if ! command -v gh >/dev/null 2>&1; then + echo "ERROR: gh CLI is not installed." >&2 + echo "Install it from https://cli.github.com/ or use GITHUB_PACKAGES_PAT instead." >&2 + exit 1 + fi + PAT="$(gh auth token)" + if [ -z "$PAT" ]; then + echo "ERROR: gh CLI is not authenticated." >&2 + echo "Run: gh auth login" >&2 + exit 1 + fi + assert_gh_packages_scope + echo "Using GitHub token from gh CLI" +else + if [ -z "${GITHUB_PACKAGES_PAT:-}" ]; then + echo "ERROR: GITHUB_PACKAGES_PAT environment variable is not set." >&2 + echo "" >&2 + echo "Please set your GitHub Personal Access Token (needs read:packages):" >&2 + echo " export GITHUB_PACKAGES_PAT=\"your_github_pat_here\"" >&2 + echo "" >&2 + echo "Or use the gh CLI shortcut:" >&2 + echo " ./scripts/configure-github-feed.sh --gh" >&2 + exit 1 + fi + PAT="$GITHUB_PACKAGES_PAT" +fi + +# Add or update the feed +echo "Checking for existing feed '$FEED_NAME'..." +if dotnet nuget list source | grep -q "$FEED_NAME"; then + echo "Found existing feed, removing..." + dotnet nuget remove source "$FEED_NAME" >/dev/null 2>&1 || true +fi + +echo "Adding GitHub Packages feed..." +echo " Name: $FEED_NAME" +echo " URL: $FEED_URL" + +dotnet nuget add source "$FEED_URL" \ + --name "$FEED_NAME" \ + --username "$FORK_OWNER" \ + --password "$PAT" \ + --store-password-in-clear-text + +echo "" +echo "✓ GitHub Packages feed configured successfully!" +echo "" +echo "You can now restore packages from your fork:" +echo " dotnet restore" +echo "" +echo "Configured sources:" +dotnet nuget list source From d10dddea4f09d5ab53e55f11b687acd88543cb13 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 11:39:45 +0100 Subject: [PATCH 17/30] Add scene manifest configuration and update SceneDelegate for UIWindow setup --- .../Firebase/AppCheck/AppCheckSample/Info.plist | 17 +++++++++++++++++ .../AppCheck/AppCheckSample/SceneDelegate.cs | 12 +++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/samples/Firebase/AppCheck/AppCheckSample/Info.plist b/samples/Firebase/AppCheck/AppCheckSample/Info.plist index b3c854650..0c7e4fe7c 100644 --- a/samples/Firebase/AppCheck/AppCheckSample/Info.plist +++ b/samples/Firebase/AppCheck/AppCheckSample/Info.plist @@ -12,6 +12,23 @@ 1.0 LSRequiresIPhoneOS + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + + + + UIDeviceFamily 1 diff --git a/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs b/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs index 1697899e5..42a5e9535 100644 --- a/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs +++ b/samples/Firebase/AppCheck/AppCheckSample/SceneDelegate.cs @@ -9,9 +9,15 @@ public class SceneDelegate : UIResponder, IUIWindowSceneDelegate { [Export ("scene:willConnectToSession:options:")] public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead). + if (scene is not UIWindowScene windowScene) { + return; + } + + Window = new UIWindow (windowScene) { + RootViewController = AppDelegate.CreateRootViewController () + }; + + Window.MakeKeyAndVisible (); } [Export ("sceneDidDisconnect:")] From 0df4eb4390a50fdf949b290d508b8177a02635ee Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 11:40:11 +0100 Subject: [PATCH 18/30] Refactor AppDelegate to improve Firebase configuration and layout constraints --- .../AppCheck/AppCheckSample/AppDelegate.cs | 69 +++++++++++-------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs b/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs index bf6093e82..c7bc656c6 100644 --- a/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs +++ b/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs @@ -1,46 +1,57 @@ -using Xamarin.iOS.Shared.Helpers; - namespace AppCheckSample; using FirebaseAppCheck = Firebase.AppCheck.AppCheck; using FirebaseCoreApp = Firebase.Core.App; +using Xamarin.iOS.Shared.Helpers; +using Xamarin.iOS.Shared.ViewControllers; [Register ("AppDelegate")] public class AppDelegate : UIApplicationDelegate { - public override UIWindow? Window { - get; - set; - } + static bool IsFirebaseConfigured { get; set; } - public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) + public override bool FinishedLaunching (UIApplication application, NSDictionary? launchOptions) { - // create a new window instance based on the screen size - Window = new UIWindow (UIScreen.MainScreen.Bounds); - - // You can download your GoogleService-Info.plist file following the next link: - // https://firebase.google.com/docs/ios/setup - if (!GoogleServiceInfoPlistHelper.FileExist ()) { - Window = GoogleServiceInfoPlistHelper.CreateWindowWithFileNotFoundMessage (); - return true; + if (GoogleServiceInfoPlistHelper.FileExist () && !IsFirebaseConfigured) { + FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.AppCheckDebugProviderFactory ()); + FirebaseCoreApp.Configure (); + IsFirebaseConfigured = true; } - FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.AppCheckDebugProviderFactory ()); - FirebaseCoreApp.Configure (); + return true; + } - var vc = new UIViewController (); - vc.View!.BackgroundColor = UIColor.White; + public override UISceneConfiguration GetConfiguration ( + UIApplication application, + UISceneSession connectingSceneSession, + UISceneConnectionOptions options) + { + return UISceneConfiguration.Create ("Default Configuration", connectingSceneSession.Role); + } + + internal static UIViewController CreateRootViewController () + { + return GoogleServiceInfoPlistHelper.FileExist () + ? CreateTokenViewController () + : new GoogleServiceInfoPlistNotFoundViewController (); + } - var statusLabel = new UILabel (new CGRect (24, 140, Window!.Frame.Width - 48, 200)) { + static UIViewController CreateTokenViewController () + { + var viewController = new UIViewController (); + viewController.View!.BackgroundColor = UIColor.White; + + var statusLabel = new UILabel { BackgroundColor = UIColor.White, TextColor = UIColor.Black, TextAlignment = UITextAlignment.Center, Lines = 0, + TranslatesAutoresizingMaskIntoConstraints = false, Text = "Firebase App Check sample\nMode: Debug provider\nTap the button to fetch a token." }; var tokenButton = UIButton.FromType (UIButtonType.System); - tokenButton.Frame = new CGRect (24, 360, Window!.Frame.Width - 48, 48); tokenButton.SetTitle ("Fetch App Check Token", UIControlState.Normal); + tokenButton.TranslatesAutoresizingMaskIntoConstraints = false; tokenButton.TouchUpInside += (_, _) => { statusLabel.Text = "Fetching App Check token..."; FirebaseAppCheck.SharedInstance.TokenForcingRefresh (true, (token, error) => { @@ -62,13 +73,17 @@ public override bool FinishedLaunching (UIApplication application, NSDictionary }); }; - vc.View.AddSubview (statusLabel); - vc.View.AddSubview (tokenButton); - Window.RootViewController = vc; + viewController.View.AddSubview (statusLabel); + viewController.View.AddSubview (tokenButton); - // make the window visible - Window.MakeKeyAndVisible (); + NSLayoutConstraint.ActivateConstraints (new [] { + statusLabel.LeadingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.LeadingAnchor, 24), + statusLabel.TrailingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TrailingAnchor, -24), + statusLabel.TopAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TopAnchor, 120), + tokenButton.TopAnchor.ConstraintEqualTo (statusLabel.BottomAnchor, 24), + tokenButton.CenterXAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.CenterXAnchor) + }); - return true; + return viewController; } } From 631256595d4e4895ae87fce2757bb00eb87e4b22 Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 13:26:19 +0100 Subject: [PATCH 19/30] fix: update Firebase AppCheck dependencies to include Installations --- components.cake | 2 +- .../AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj | 2 ++ samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj | 2 ++ source/Firebase/AppCheck/AppCheck.csproj | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components.cake b/components.cake index f9d5f5c37..c2159424e 100644 --- a/components.cake +++ b/components.cake @@ -115,7 +115,7 @@ void SetArtifactsDependencies () FIREBASE_REMOTE_CONFIG_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT, FIREBASE_AB_TESTING_ARTIFACT }; FIREBASE_STORAGE_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_DATABASE_ARTIFACT, GOOGLE_GTM_SESSION_FETCHER_ARTIFACT /* Needed for sample FIREBASE_AUTH_ARTIFACT */ }; // FIREBASE_APP_DISTRIBUTION_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT }; - FIREBASE_APP_CHECK_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT }; + FIREBASE_APP_CHECK_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT, GOOGLE_APP_CHECK_CORE_ARTIFACT }; GOOGLE_ANALYTICS_ARTIFACT.Dependencies = null; GOOGLE_CAST_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT }; diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj index 461670af6..7a20245ae 100644 --- a/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj +++ b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.NuGet.csproj @@ -17,6 +17,7 @@ Debug;Release false manual + $(DefaultItemExcludes);obj/AppCheckSample/**;bin/AppCheckSample/** true @@ -69,5 +70,6 @@ + diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj index 38e177eaa..7df9ed1d1 100644 --- a/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj +++ b/samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj @@ -17,6 +17,7 @@ Debug;Release false manual + $(DefaultItemExcludes);obj/AppCheckSample.NuGet/**;bin/AppCheckSample.NuGet/** true @@ -68,6 +69,7 @@ + diff --git a/source/Firebase/AppCheck/AppCheck.csproj b/source/Firebase/AppCheck/AppCheck.csproj index 8d3638602..6613c9ed0 100644 --- a/source/Firebase/AppCheck/AppCheck.csproj +++ b/source/Firebase/AppCheck/AppCheck.csproj @@ -54,5 +54,6 @@ + From de3de97b531ef732b37000f06ef46a3af4f1a17a Mon Sep 17 00:00:00 2001 From: kapusch Date: Tue, 3 Feb 2026 22:08:05 +0100 Subject: [PATCH 20/30] feat: add README for Firebase App Check sample with setup instructions and troubleshooting --- .../AppCheck/AppCheckSample/README.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 samples/Firebase/AppCheck/AppCheckSample/README.md diff --git a/samples/Firebase/AppCheck/AppCheckSample/README.md b/samples/Firebase/AppCheck/AppCheckSample/README.md new file mode 100644 index 000000000..0986e911b --- /dev/null +++ b/samples/Firebase/AppCheck/AppCheckSample/README.md @@ -0,0 +1,75 @@ +# Firebase App Check — AppCheckSample (iOS) + +This sample validates the **Firebase App Check iOS** bindings in a real app. + +## Prerequisites + +- A Firebase project with an **iOS app** registered. +- A real device is strongly recommended. + - Simulator runs can fail with keychain/attestation related issues and may not be representative. +- Add `GoogleService-Info.plist` next to the sample project (do **not** commit secrets): + - `samples/Firebase/AppCheck/AppCheckSample/GoogleService-Info.plist` + +## App Check (Debug) — Two workflows + +Both workflows end up with the same outcome: +- Firebase Console knows your **debug token**. +- The app injects the same token at runtime. + +### Workflow A — Get token from app logs, then register it in Firebase Console + +1) Run the app once (see command below) and watch the console output. + +2) Copy the debug token printed by the Firebase SDK. + +3) Firebase Console: +- Go to **App Check** → select your iOS app → **Manage Debug tokens**. +- Paste the debug token value you copied. + +4) In the sample app, tap on the `Fetch App Check Token` button: the test should succeed. + +### Workflow B — Generate your own token in Firebase Console, then inject it at build/run time + +This is useful when you want a deterministic token without first scraping logs. + +1) Firebase Console: +- Go to **App Check** → select your iOS app → **Manage Debug tokens**. +- Generate a new debug token and copy its value. + +2) Inject that same value when launching the app using `FIRAAppCheckDebugToken` (see command below). + +3) In the sample app, tap on the `Fetch App Check Token` button: the test should succeed. + +## Run on a real device (recommended) + +Replace: +- `UDID` with your device UDID +- `YOUR_DEBUG_TOKEN` with your debug token (Workflow B only) + +```bash +dotnet build samples/Firebase/AppCheck/AppCheckSample/AppCheckSample.csproj \ + -c Debug -f net9.0-ios -t:Run \ + -p:Platform=iPhone -p:RuntimeIdentifier=ios-arm64 \ + -p:_DeviceName=UDID \ + -p:_BundlerDebug=true -v:n \ + -p:MlaunchAdditionalArgumentsProperty="--setenv=FIRAAppCheckDebugToken=YOUR_DEBUG_TOKEN" +``` + +Note: on some setups `mlaunch` expects `_DeviceName` to be the **raw UDID** (no `:v2:udid=` prefix). + +## Troubleshooting + +- **`403 PERMISSION_DENIED` / `App attestation failed`** + - The debug token is not registered for this Firebase app, or you’re using the wrong Firebase project / `GoogleService-Info.plist`. + +- **`Keychain access error` (often on simulator)** + - Prefer real device. + - If you must use simulator, try a fresh simulator device and reinstall. + +- **No Firebase configured UI / missing plist** + - Ensure `GoogleService-Info.plist` is present at: + - `samples/Firebase/AppCheck/AppCheckSample/GoogleService-Info.plist` + +## What success looks like + +The UI action to fetch an App Check token returns successfully. From 5f2ddd54018805e73607ec610c2c79c4b741069f Mon Sep 17 00:00:00 2001 From: kapusch Date: Wed, 4 Feb 2026 00:34:57 +0100 Subject: [PATCH 21/30] Firebase.AppCheck: expose provider factory API (fork) --- source/Firebase/AppCheck/ApiDefinition.cs | 20 ++++++++++---------- source/Firebase/AppCheck/AppCheck.csproj | 10 +++++++--- source/Firebase/AppCheck/Extensions.cs | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 source/Firebase/AppCheck/Extensions.cs diff --git a/source/Firebase/AppCheck/ApiDefinition.cs b/source/Firebase/AppCheck/ApiDefinition.cs index 15c87d8ee..0467fc1e8 100644 --- a/source/Firebase/AppCheck/ApiDefinition.cs +++ b/source/Firebase/AppCheck/ApiDefinition.cs @@ -51,8 +51,9 @@ interface AppCheck { } // @protocol FIRAppCheckProvider - [Protocol] - [BaseType (typeof (NSObject), Name = "FIRAppCheckProvider")] + interface IAppCheckProvider { } + + [Protocol (Name = "FIRAppCheckProvider")] interface AppCheckProvider { // @required -(void)getTokenWithCompletion:(void (^ _Nonnull)(FIRAppCheckToken * _Nullable, NSError * _Nullable))handler __attribute__((swift_name("getToken(completion:)"))); [Abstract] @@ -61,14 +62,13 @@ interface AppCheckProvider { } // @protocol FIRAppCheckProviderFactory - [Protocol] - [BaseType (typeof (NSObject), Name = "FIRAppCheckProviderFactory")] + [Protocol (Name = "FIRAppCheckProviderFactory")] interface AppCheckProviderFactory { // @required -(id _Nullable)createProviderWithApp:(FIRApp * _Nonnull)app; [Abstract] [Export ("createProviderWithApp:")] [return: NullAllowed] - AppCheckProvider CreateProviderWithApp (App app); + IAppCheckProvider CreateProviderWithApp (App app); } // @interface FIRAppCheckToken : NSObject @@ -91,7 +91,7 @@ interface AppCheckToken { // @interface FIRAppCheckDebugProvider : NSObject [DisableDefaultCtor] [BaseType (typeof (NSObject), Name = "FIRAppCheckDebugProvider")] - interface AppCheckDebugProvider : AppCheckProvider { + interface AppCheckDebugProvider : IAppCheckProvider { // -(instancetype _Nullable)initWithApp:(FIRApp * _Nonnull)app; [Export ("initWithApp:")] NativeHandle Constructor (App app); @@ -107,14 +107,14 @@ interface AppCheckDebugProvider : AppCheckProvider { // @interface FIRAppCheckDebugProviderFactory : NSObject [BaseType (typeof (NSObject), Name = "FIRAppCheckDebugProviderFactory")] - interface AppCheckDebugProviderFactory : AppCheckProviderFactory { + interface AppCheckDebugProviderFactory : IAppCheckProviderFactory { } // @interface FIRDeviceCheckProvider : NSObject //[TV (11, 0), NoWatch, Mac (10, 15), iOS (11, 0)] [DisableDefaultCtor] [BaseType (typeof (NSObject), Name = "FIRDeviceCheckProvider")] - interface DeviceCheckProvider : AppCheckProvider { + interface DeviceCheckProvider : IAppCheckProvider { // -(instancetype _Nullable)initWithApp:(FIRApp * _Nonnull)app; [Export ("initWithApp:")] NativeHandle Constructor (App app); @@ -124,7 +124,7 @@ interface DeviceCheckProvider : AppCheckProvider { //[NoTV, NoWatch, NoMac, iOS (14, 0)] [DisableDefaultCtor] [BaseType (typeof (NSObject), Name = "FIRAppAttestProvider")] - interface AppAttestProvider : AppCheckProvider { + interface AppAttestProvider : IAppCheckProvider { // -(instancetype _Nullable)initWithApp:(FIRApp * _Nonnull)app; [Export ("initWithApp:")] NativeHandle Constructor (App app); @@ -133,6 +133,6 @@ interface AppAttestProvider : AppCheckProvider { // @interface FIRDeviceCheckProviderFactory : NSObject //[TV (11, 0), NoWatch, Mac (10, 15), iOS (11, 0)] [BaseType (typeof (NSObject), Name = "FIRDeviceCheckProviderFactory")] - interface DeviceCheckProviderFactory : AppCheckProviderFactory { + interface DeviceCheckProviderFactory : IAppCheckProviderFactory { } } diff --git a/source/Firebase/AppCheck/AppCheck.csproj b/source/Firebase/AppCheck/AppCheck.csproj index 6613c9ed0..894bed491 100644 --- a/source/Firebase/AppCheck/AppCheck.csproj +++ b/source/Firebase/AppCheck/AppCheck.csproj @@ -26,7 +26,7 @@ https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md true - 12.5.0.4 + 12.5.0.4-fork @@ -53,7 +53,11 @@ - - + + PackageVersion + + + PackageVersion + diff --git a/source/Firebase/AppCheck/Extensions.cs b/source/Firebase/AppCheck/Extensions.cs new file mode 100644 index 000000000..facfa1003 --- /dev/null +++ b/source/Firebase/AppCheck/Extensions.cs @@ -0,0 +1,14 @@ +namespace Firebase.AppCheck; + +public partial class AppCheck +{ + public static void SetAppCheckProviderFactory (AppCheckDebugProviderFactory factory) + { + SetAppCheckProviderFactory ((IAppCheckProviderFactory) factory); + } + + public static void SetAppCheckProviderFactory (DeviceCheckProviderFactory factory) + { + SetAppCheckProviderFactory ((IAppCheckProviderFactory) factory); + } +} From 1d89e731b3127efc30b960a4753cc6f99d74cb6a Mon Sep 17 00:00:00 2001 From: kapusch Date: Wed, 4 Feb 2026 12:59:47 +0100 Subject: [PATCH 22/30] fix: update versioning logic in common.cake to handle pre-release suffixes --- CONTRIBUTING.md | 9 +++++++++ common.cake | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 965f82b55..d5b6e5553 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,6 +42,15 @@ Most contributions fall into one of these buckets: * **Signing vs build-only**: device builds require provisioning; CI should validate “build-only” (no signing) where possible. * **URL scheme callbacks**: OAuth-style flows often require `Info.plist` URL scheme changes in addition to config files. +## Versioning notes (Cake vs .csproj) + +The Cake pipeline updates versions in binding `.csproj` files during the `externals` step: + +* `FileVersion` is always set to `artifact.NugetVersion` (from `components.cake`). +* `PackageVersion` is set to `artifact.NugetVersion` **unless** the project already specifies a pre-release suffix (e.g. `12.5.0.4-fork`). + +This allows forked builds to publish `-fork` (or similar) packages without changing the shared component version line in `components.cake`, while keeping deterministic, aligned build outputs. + ## Validation checklist (before requesting review) At minimum, validate the component(s) you touched: diff --git a/common.cake b/common.cake index 4a6d07e39..83b875afe 100644 --- a/common.cake +++ b/common.cake @@ -61,7 +61,9 @@ void UpdateVersionInCsproj (Artifact artifact) var componentGroup = artifact.ComponentGroup.ToString (); var csprojPath = $"./source/{componentGroup}/{artifact.CsprojName}/{artifact.CsprojName}.csproj"; XmlPoke(csprojPath, "/Project/PropertyGroup/FileVersion", artifact.NugetVersion); - XmlPoke(csprojPath, "/Project/PropertyGroup/PackageVersion", artifact.NugetVersion); + var currentPackageVersion = XmlPeek(csprojPath, "/Project/PropertyGroup/PackageVersion"); + if (!currentPackageVersion.Contains("-")) + XmlPoke(csprojPath, "/Project/PropertyGroup/PackageVersion", artifact.NugetVersion); } void CreateAndInstallPodfile (Artifact artifact) From da10f82fc043ad3cf6cda50589880e5e5c01a723 Mon Sep 17 00:00:00 2001 From: kapusch Date: Thu, 5 Feb 2026 00:06:53 +0100 Subject: [PATCH 23/30] fix(appcheck): avoid protocol cast via objc_msgSend --- source/Firebase/AppCheck/Extensions.cs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/source/Firebase/AppCheck/Extensions.cs b/source/Firebase/AppCheck/Extensions.cs index facfa1003..a6a845c8f 100644 --- a/source/Firebase/AppCheck/Extensions.cs +++ b/source/Firebase/AppCheck/Extensions.cs @@ -1,14 +1,32 @@ +using Foundation; +using ObjCRuntime; + namespace Firebase.AppCheck; public partial class AppCheck { - public static void SetAppCheckProviderFactory (AppCheckDebugProviderFactory factory) + ///

+ /// Calls FIRAppCheck.setAppCheckProviderFactory: using ApiDefinition.Messaging. + /// This bypasses C# protocol interface cast issues that occur at runtime with ObjC bindings. + /// Uses the same pattern as auto-generated binding code. + /// + private static void SetAppCheckProviderFactoryNative(NSObject factory) + { + // Call: +[FIRAppCheck setAppCheckProviderFactory:] + // Using ApiDefinition.Messaging (generated by binding tooling, same as ObjCRuntime.Messaging pattern) + global::ApiDefinition.Messaging.void_objc_msgSend_NativeHandle( + Class.GetHandle("FIRAppCheck"), + Selector.GetHandle("setAppCheckProviderFactory:"), + factory?.GetNonNullHandle(nameof(factory)) ?? default); + } + + public static void SetAppCheckProviderFactory(AppCheckDebugProviderFactory factory) { - SetAppCheckProviderFactory ((IAppCheckProviderFactory) factory); + SetAppCheckProviderFactoryNative(factory); } - public static void SetAppCheckProviderFactory (DeviceCheckProviderFactory factory) + public static void SetAppCheckProviderFactory(DeviceCheckProviderFactory factory) { - SetAppCheckProviderFactory ((IAppCheckProviderFactory) factory); + SetAppCheckProviderFactoryNative(factory); } } From 252d7f3f5586f85f11a4ed2558e37ad144a4db9d Mon Sep 17 00:00:00 2001 From: kapusch Date: Thu, 5 Feb 2026 00:06:56 +0100 Subject: [PATCH 24/30] docs: document -local vs -fork workflow --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5b6e5553..1db2f1784 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,6 +51,22 @@ The Cake pipeline updates versions in binding `.csproj` files during the `extern This allows forked builds to publish `-fork` (or similar) packages without changing the shared component version line in `components.cake`, while keeping deterministic, aligned build outputs. +## Fork testing suffix policy (`-local` vs `-fork`) + +When validating a binding fix before upstream release: + +* Use `-local` for packages built on a developer machine and consumed from a local NuGet source. +* Use `-fork` for packages built by your fork CI and published to GitHub Packages. + +Suggested flow: + +1. Set a temporary prerelease `PackageVersion` (for example `12.5.0.4-fork` or `12.5.0.4-local`) in the affected project(s). +2. Build/publish from the matching channel (local machine for `-local`, GitHub Actions for `-fork`). +3. Consume that package from downstream repos to validate the fix. +4. Before opening an upstream PR, revert temporary prerelease versions/references back to the canonical version line expected upstream. + +Important: do not merge or submit upstream PRs with temporary fork-only or local-only package versions unless explicitly requested by maintainers. + ## Validation checklist (before requesting review) At minimum, validate the component(s) you touched: From 3139dea9bc174d61cd2dca1d38cfec535dbe2eda Mon Sep 17 00:00:00 2001 From: kapusch Date: Fri, 6 Feb 2026 13:00:18 +0100 Subject: [PATCH 25/30] fix: update package version to remove fork suffix --- source/Firebase/AppCheck/AppCheck.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Firebase/AppCheck/AppCheck.csproj b/source/Firebase/AppCheck/AppCheck.csproj index 894bed491..ff0663d30 100644 --- a/source/Firebase/AppCheck/AppCheck.csproj +++ b/source/Firebase/AppCheck/AppCheck.csproj @@ -26,7 +26,7 @@ https://github.com/AdamEssenmacher/GoogleApisForiOSComponents License.md true - 12.5.0.4-fork + 12.5.0.4 From 323874ba2e90a329a1f8a582accf18abce53879b Mon Sep 17 00:00:00 2001 From: kapusch Date: Fri, 6 Feb 2026 13:01:47 +0100 Subject: [PATCH 26/30] fix(signin): replace AppCheckCore package reference with project reference --- build.cake | 3 ++- source/Google/SignIn/SignIn.csproj | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index dc048fbdd..9f0c5b6ef 100644 --- a/build.cake +++ b/build.cake @@ -201,7 +201,8 @@ Task ("samples") var dotNetCoreBuildSettings = new DotNetCoreBuildSettings { Configuration = "Release", Verbosity = DotNetCoreVerbosity.Diagnostic, - NoRestore = false + NoRestore = false, + MSBuildSettings = msBuildSettings }; // Build each sample csproj directly diff --git a/source/Google/SignIn/SignIn.csproj b/source/Google/SignIn/SignIn.csproj index 74b4de757..7a54d4ef2 100644 --- a/source/Google/SignIn/SignIn.csproj +++ b/source/Google/SignIn/SignIn.csproj @@ -75,6 +75,10 @@ - + + + + PackageVersion +
From 5877a00b12180c16eca7cb2426922ee4f875275a Mon Sep 17 00:00:00 2001 From: kapusch Date: Fri, 6 Feb 2026 19:09:48 +0100 Subject: [PATCH 27/30] fix(appcheck): update SetAppCheckProviderFactory and CreateProviderWithApp to use NSObject instead of interfaces --- source/Firebase/AppCheck/ApiDefinition.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Firebase/AppCheck/ApiDefinition.cs b/source/Firebase/AppCheck/ApiDefinition.cs index 0467fc1e8..ac4f0758c 100644 --- a/source/Firebase/AppCheck/ApiDefinition.cs +++ b/source/Firebase/AppCheck/ApiDefinition.cs @@ -43,7 +43,7 @@ interface AppCheck { // +(void)setAppCheckProviderFactory:(id _Nullable)factory; [Static] [Export ("setAppCheckProviderFactory:")] - void SetAppCheckProviderFactory ([NullAllowed] IAppCheckProviderFactory factory); + void SetAppCheckProviderFactory ([NullAllowed] NSObject factory); // @property (assign, nonatomic) BOOL isTokenAutoRefreshEnabled; [Export ("isTokenAutoRefreshEnabled")] @@ -68,7 +68,7 @@ interface AppCheckProviderFactory { [Abstract] [Export ("createProviderWithApp:")] [return: NullAllowed] - IAppCheckProvider CreateProviderWithApp (App app); + NSObject CreateProviderWithApp (App app); } // @interface FIRAppCheckToken : NSObject From 9ff9642e1e4d101539a481fa8187753d0eaae45e Mon Sep 17 00:00:00 2001 From: kapusch Date: Sat, 7 Feb 2026 00:00:14 +0100 Subject: [PATCH 28/30] fix(appcheck): update artifact dependencies and add package references for PromisesObjC and GoogleUtilities to AppCheckCore.csproj --- components.cake | 10 +++++----- source/Google/AppCheckCore/AppCheckCore.csproj | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components.cake b/components.cake index b97a7d942..4282db6ff 100644 --- a/components.cake +++ b/components.cake @@ -65,7 +65,7 @@ var ARTIFACTS = new Dictionary { { "Firebase.RemoteConfig", FIREBASE_REMOTE_CONFIG_ARTIFACT }, { "Firebase.Storage", FIREBASE_STORAGE_ARTIFACT }, // { "Firebase.AppDistribution", FIREBASE_APP_DISTRIBUTION_ARTIFACT }, - { "Firebase.AppCheck", FIREBASE_APP_CHECK_ARTIFACT }, + { "Firebase.AppCheck", FIREBASE_APP_CHECK_ARTIFACT }, { "Google.GoogleAppMeasurement", GOOGLE_GOOGLE_APP_MEASUREMENT_ARTIFACT }, { "Google.Analytics", GOOGLE_ANALYTICS_ARTIFACT }, @@ -74,9 +74,9 @@ var ARTIFACTS = new Dictionary { { "Google.MobileAds", GOOGLE_MOBILE_ADS_ARTIFACT }, { "Google.UserMessagingPlatform", GOOGLE_UMP_ARTIFACT }, { "Google.Places", GOOGLE_PLACES_ARTIFACT }, - { "Google.SignIn", GOOGLE_SIGN_IN_ARTIFACT }, - { "Google.AppCheckCore", GOOGLE_APP_CHECK_CORE_ARTIFACT }, - { "Google.TagManager", GOOGLE_TAG_MANAGER_ARTIFACT }, + { "Google.SignIn", GOOGLE_SIGN_IN_ARTIFACT }, + { "Google.AppCheckCore", GOOGLE_APP_CHECK_CORE_ARTIFACT }, + { "Google.TagManager", GOOGLE_TAG_MANAGER_ARTIFACT }, { "Google.GTMSessionFetcher", GOOGLE_GTM_SESSION_FETCHER_ARTIFACT }, { "Google.PromisesObjC", GOOGLE_PROMISES_OBJC_ARTIFACT }, { "Google.Nanopb", GOOGLE_NANOPB_ARTIFACT }, @@ -125,7 +125,7 @@ void SetArtifactsDependencies () GOOGLE_PLACES_ARTIFACT.Dependencies = null; GOOGLE_SIGN_IN_ARTIFACT.Dependencies = new [] { GOOGLE_GTM_SESSION_FETCHER_ARTIFACT, GOOGLE_PROMISES_OBJC_ARTIFACT, GOOGLE_GOOGLE_UTILITIES_ARTIFACT, GOOGLE_APP_CHECK_CORE_ARTIFACT }; GOOGLE_TAG_MANAGER_ARTIFACT.Dependencies = new [] { FIREBASE_CORE_ARTIFACT, FIREBASE_INSTALLATIONS_ARTIFACT, FIREBASE_ANALYTICS_ARTIFACT }; - GOOGLE_APP_CHECK_CORE_ARTIFACT.Dependencies = null; + GOOGLE_APP_CHECK_CORE_ARTIFACT.Dependencies = new [] { GOOGLE_PROMISES_OBJC_ARTIFACT, GOOGLE_GOOGLE_UTILITIES_ARTIFACT }; GOOGLE_PROMISES_OBJC_ARTIFACT.Dependencies = null; GOOGLE_GTM_SESSION_FETCHER_ARTIFACT.Dependencies = null; GOOGLE_NANOPB_ARTIFACT.Dependencies = null; diff --git a/source/Google/AppCheckCore/AppCheckCore.csproj b/source/Google/AppCheckCore/AppCheckCore.csproj index 2dad4caff..446150db8 100644 --- a/source/Google/AppCheckCore/AppCheckCore.csproj +++ b/source/Google/AppCheckCore/AppCheckCore.csproj @@ -46,4 +46,8 @@ + + + +
From 329eb3e873d5fc088dba96ad86d958c93a633aa2 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sat, 7 Feb 2026 13:07:45 +0100 Subject: [PATCH 29/30] fix(appcheck): refactor AppCheck provider interfaces and remove Extensions.cs --- source/Firebase/AppCheck/ApiDefinition.cs | 14 ++++++---- source/Firebase/AppCheck/Extensions.cs | 32 ----------------------- 2 files changed, 9 insertions(+), 37 deletions(-) delete mode 100644 source/Firebase/AppCheck/Extensions.cs diff --git a/source/Firebase/AppCheck/ApiDefinition.cs b/source/Firebase/AppCheck/ApiDefinition.cs index ac4f0758c..61371f46b 100644 --- a/source/Firebase/AppCheck/ApiDefinition.cs +++ b/source/Firebase/AppCheck/ApiDefinition.cs @@ -43,7 +43,7 @@ interface AppCheck { // +(void)setAppCheckProviderFactory:(id _Nullable)factory; [Static] [Export ("setAppCheckProviderFactory:")] - void SetAppCheckProviderFactory ([NullAllowed] NSObject factory); + void SetAppCheckProviderFactory ([NullAllowed] IAppCheckProviderFactory factory); // @property (assign, nonatomic) BOOL isTokenAutoRefreshEnabled; [Export ("isTokenAutoRefreshEnabled")] @@ -53,6 +53,8 @@ interface AppCheck { // @protocol FIRAppCheckProvider interface IAppCheckProvider { } + [Model] + [BaseType (typeof (NSObject))] [Protocol (Name = "FIRAppCheckProvider")] interface AppCheckProvider { // @required -(void)getTokenWithCompletion:(void (^ _Nonnull)(FIRAppCheckToken * _Nullable, NSError * _Nullable))handler __attribute__((swift_name("getToken(completion:)"))); @@ -62,6 +64,8 @@ interface AppCheckProvider { } // @protocol FIRAppCheckProviderFactory + [Model] + [BaseType (typeof (NSObject))] [Protocol (Name = "FIRAppCheckProviderFactory")] interface AppCheckProviderFactory { // @required -(id _Nullable)createProviderWithApp:(FIRApp * _Nonnull)app; @@ -107,14 +111,14 @@ interface AppCheckDebugProvider : IAppCheckProvider { // @interface FIRAppCheckDebugProviderFactory : NSObject [BaseType (typeof (NSObject), Name = "FIRAppCheckDebugProviderFactory")] - interface AppCheckDebugProviderFactory : IAppCheckProviderFactory { + interface AppCheckDebugProviderFactory : AppCheckProviderFactory { } // @interface FIRDeviceCheckProvider : NSObject //[TV (11, 0), NoWatch, Mac (10, 15), iOS (11, 0)] [DisableDefaultCtor] [BaseType (typeof (NSObject), Name = "FIRDeviceCheckProvider")] - interface DeviceCheckProvider : IAppCheckProvider { + interface DeviceCheckProvider : AppCheckProvider { // -(instancetype _Nullable)initWithApp:(FIRApp * _Nonnull)app; [Export ("initWithApp:")] NativeHandle Constructor (App app); @@ -124,7 +128,7 @@ interface DeviceCheckProvider : IAppCheckProvider { //[NoTV, NoWatch, NoMac, iOS (14, 0)] [DisableDefaultCtor] [BaseType (typeof (NSObject), Name = "FIRAppAttestProvider")] - interface AppAttestProvider : IAppCheckProvider { + interface AppAttestProvider : AppCheckProvider { // -(instancetype _Nullable)initWithApp:(FIRApp * _Nonnull)app; [Export ("initWithApp:")] NativeHandle Constructor (App app); @@ -133,6 +137,6 @@ interface AppAttestProvider : IAppCheckProvider { // @interface FIRDeviceCheckProviderFactory : NSObject //[TV (11, 0), NoWatch, Mac (10, 15), iOS (11, 0)] [BaseType (typeof (NSObject), Name = "FIRDeviceCheckProviderFactory")] - interface DeviceCheckProviderFactory : IAppCheckProviderFactory { + interface DeviceCheckProviderFactory : AppCheckProviderFactory { } } diff --git a/source/Firebase/AppCheck/Extensions.cs b/source/Firebase/AppCheck/Extensions.cs deleted file mode 100644 index a6a845c8f..000000000 --- a/source/Firebase/AppCheck/Extensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Foundation; -using ObjCRuntime; - -namespace Firebase.AppCheck; - -public partial class AppCheck -{ - /// - /// Calls FIRAppCheck.setAppCheckProviderFactory: using ApiDefinition.Messaging. - /// This bypasses C# protocol interface cast issues that occur at runtime with ObjC bindings. - /// Uses the same pattern as auto-generated binding code. - /// - private static void SetAppCheckProviderFactoryNative(NSObject factory) - { - // Call: +[FIRAppCheck setAppCheckProviderFactory:] - // Using ApiDefinition.Messaging (generated by binding tooling, same as ObjCRuntime.Messaging pattern) - global::ApiDefinition.Messaging.void_objc_msgSend_NativeHandle( - Class.GetHandle("FIRAppCheck"), - Selector.GetHandle("setAppCheckProviderFactory:"), - factory?.GetNonNullHandle(nameof(factory)) ?? default); - } - - public static void SetAppCheckProviderFactory(AppCheckDebugProviderFactory factory) - { - SetAppCheckProviderFactoryNative(factory); - } - - public static void SetAppCheckProviderFactory(DeviceCheckProviderFactory factory) - { - SetAppCheckProviderFactoryNative(factory); - } -} From 9ee57a36ead0e344a3a69345e13d00f534e8fc94 Mon Sep 17 00:00:00 2001 From: kapusch Date: Sat, 7 Feb 2026 14:54:08 +0100 Subject: [PATCH 30/30] Enable AppCheck mode selection and configuration in sample app --- .../AppCheck/AppCheckSample/AppDelegate.cs | 223 +++++++++++++++--- 1 file changed, 188 insertions(+), 35 deletions(-) diff --git a/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs b/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs index c7bc656c6..4d770bb4a 100644 --- a/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs +++ b/samples/Firebase/AppCheck/AppCheckSample/AppDelegate.cs @@ -7,19 +7,46 @@ namespace AppCheckSample; [Register ("AppDelegate")] public class AppDelegate : UIApplicationDelegate { + const string SelectedModeKey = "SelectedAppCheckMode"; static bool IsFirebaseConfigured { get; set; } public override bool FinishedLaunching (UIApplication application, NSDictionary? launchOptions) { if (GoogleServiceInfoPlistHelper.FileExist () && !IsFirebaseConfigured) { - FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.AppCheckDebugProviderFactory ()); - FirebaseCoreApp.Configure (); - IsFirebaseConfigured = true; + // Configure Firebase with the selected AppCheck provider + var selectedMode = NSUserDefaults.StandardUserDefaults.StringForKey (SelectedModeKey); + + if (!string.IsNullOrEmpty (selectedMode)) { + ConfigureFirebaseWithMode (selectedMode); + } + // If no mode selected yet, Firebase will be configured after user selection } return true; } + static void ConfigureFirebaseWithMode (string mode) + { + switch (mode) { + case "Debug": + FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.AppCheckDebugProviderFactory ()); + break; + case "Device Check": + FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.DeviceCheckProviderFactory ()); + break; + case "App Attest": + // Note: AppAttestProviderFactory is not exposed in current bindings, using Device Check as fallback + FirebaseAppCheck.SetAppCheckProviderFactory (new Firebase.AppCheck.DeviceCheckProviderFactory ()); + break; + case "Disabled": + // Don't set any provider + break; + } + + FirebaseCoreApp.Configure (); + IsFirebaseConfigured = true; + } + public override UISceneConfiguration GetConfiguration ( UIApplication application, UISceneSession connectingSceneSession, @@ -30,15 +57,90 @@ public override UISceneConfiguration GetConfiguration ( internal static UIViewController CreateRootViewController () { - return GoogleServiceInfoPlistHelper.FileExist () - ? CreateTokenViewController () - : new GoogleServiceInfoPlistNotFoundViewController (); + if (!GoogleServiceInfoPlistHelper.FileExist ()) { + return new GoogleServiceInfoPlistNotFoundViewController (); + } + + var selectedMode = NSUserDefaults.StandardUserDefaults.StringForKey (SelectedModeKey); + + // If no mode selected yet, show selection screen + if (string.IsNullOrEmpty (selectedMode)) { + return new UINavigationController (CreateModeSelectionViewController ()); + } + + // Otherwise show the token test screen + return new UINavigationController (CreateTokenViewController (selectedMode)); + } + + static UIViewController CreateModeSelectionViewController () + { + var viewController = new UIViewController (); + viewController.View!.BackgroundColor = UIColor.White; + viewController.Title = "Select AppCheck Mode"; + + var headerLabel = new UILabel { + BackgroundColor = UIColor.White, + TextColor = UIColor.Black, + TextAlignment = UITextAlignment.Center, + Lines = 0, + Font = UIFont.BoldSystemFontOfSize (18), + TranslatesAutoresizingMaskIntoConstraints = false, + Text = "Choose an App Check mode to test.\n\nFirebase will be configured with your selection.\n\nTo test another mode, use the Reset button." + }; + + var stackView = new UIStackView { + Axis = UILayoutConstraintAxis.Vertical, + Spacing = 16, + TranslatesAutoresizingMaskIntoConstraints = false, + Alignment = UIStackViewAlignment.Fill, + Distribution = UIStackViewDistribution.FillEqually + }; + + var modes = new[] { "Disabled", "Debug", "Device Check", "App Attest" }; + foreach (var mode in modes) { + var button = UIButton.FromType (UIButtonType.System); + button.SetTitle (mode, UIControlState.Normal); + button.TitleLabel!.Font = UIFont.SystemFontOfSize (16); + button.TranslatesAutoresizingMaskIntoConstraints = false; + button.TouchUpInside += (_, _) => { + // Save selection + NSUserDefaults.StandardUserDefaults.SetString (mode, SelectedModeKey); + NSUserDefaults.StandardUserDefaults.Synchronize (); + + // Configure Firebase if not already done + if (!IsFirebaseConfigured) { + ConfigureFirebaseWithMode (mode); + } + + // Navigate to token test screen + var tokenVC = CreateTokenViewController (mode); + viewController.NavigationController?.PushViewController (tokenVC, true); + }; + stackView.AddArrangedSubview (button); + } + + viewController.View.AddSubview (headerLabel); + viewController.View.AddSubview (stackView); + + NSLayoutConstraint.ActivateConstraints (new [] { + headerLabel.LeadingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.LeadingAnchor, 24), + headerLabel.TrailingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TrailingAnchor, -24), + headerLabel.TopAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TopAnchor, 40), + + stackView.LeadingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.LeadingAnchor, 40), + stackView.TrailingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TrailingAnchor, -40), + stackView.TopAnchor.ConstraintEqualTo (headerLabel.BottomAnchor, 40), + stackView.BottomAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.BottomAnchor, -120) + }); + + return viewController; } - static UIViewController CreateTokenViewController () + static UIViewController CreateTokenViewController (string mode) { var viewController = new UIViewController (); viewController.View!.BackgroundColor = UIColor.White; + viewController.Title = $"AppCheck: {mode}"; var statusLabel = new UILabel { BackgroundColor = UIColor.White, @@ -46,43 +148,94 @@ static UIViewController CreateTokenViewController () TextAlignment = UITextAlignment.Center, Lines = 0, TranslatesAutoresizingMaskIntoConstraints = false, - Text = "Firebase App Check sample\nMode: Debug provider\nTap the button to fetch a token." + Text = mode == "App Attest" + ? $"Mode: {mode}\n(using Device Check as fallback)\n\nTap the button to fetch a token." + : mode == "Disabled" + ? "Mode: Disabled\n\nApp Check is not configured.\nNo provider factory was set." + : $"Mode: {mode}\n\nTap the button to fetch a token." }; - var tokenButton = UIButton.FromType (UIButtonType.System); - tokenButton.SetTitle ("Fetch App Check Token", UIControlState.Normal); - tokenButton.TranslatesAutoresizingMaskIntoConstraints = false; - tokenButton.TouchUpInside += (_, _) => { - statusLabel.Text = "Fetching App Check token..."; - FirebaseAppCheck.SharedInstance.TokenForcingRefresh (true, (token, error) => { - UIApplication.SharedApplication.BeginInvokeOnMainThread (() => { - if (error is not null) { - statusLabel.Text = $"Token request failed:\n{error.LocalizedDescription}"; - return; - } - - if (token is null || string.IsNullOrWhiteSpace (token.Token)) { - statusLabel.Text = "Token request returned an empty response."; - return; - } - - var rawToken = token.Token; - var preview = rawToken.Length > 20 ? $"{rawToken[..12]}...{rawToken[^8..]}" : rawToken; - statusLabel.Text = $"Token OK\n{preview}\nExpires: {token.ExpirationDate}"; + UIButton? tokenButton = null; + if (mode != "Disabled") { + tokenButton = UIButton.FromType (UIButtonType.System); + tokenButton.SetTitle ("Fetch App Check Token", UIControlState.Normal); + tokenButton.TranslatesAutoresizingMaskIntoConstraints = false; + tokenButton.TouchUpInside += (_, _) => { + statusLabel.Text = "Fetching App Check token..."; + FirebaseAppCheck.SharedInstance.TokenForcingRefresh (true, (token, error) => { + UIApplication.SharedApplication.BeginInvokeOnMainThread (() => { + if (error is not null) { + statusLabel.Text = $"Token request failed:\n{error.LocalizedDescription}"; + return; + } + + if (token is null || string.IsNullOrWhiteSpace (token.Token)) { + statusLabel.Text = "Token request returned an empty response."; + return; + } + + var rawToken = token.Token; + var preview = rawToken.Length > 20 ? $"{rawToken[..12]}...{rawToken[^8..]}" : rawToken; + statusLabel.Text = $"Token OK\n{preview}\nExpires: {token.ExpirationDate}"; + }); }); - }); + }; + } + + var resetButton = UIButton.FromType (UIButtonType.System); + resetButton.SetTitle ("Reset Mode (Restart Required)", UIControlState.Normal); + resetButton.SetTitleColor (UIColor.Red, UIControlState.Normal); + resetButton.TranslatesAutoresizingMaskIntoConstraints = false; + resetButton.TouchUpInside += (_, _) => { + var alert = UIAlertController.Create ( + "Reset App Check Mode", + "This will clear the selected mode. You must restart the app to select a new mode.\n\nNote: Firebase can only be configured once per app session.", + UIAlertControllerStyle.Alert + ); + alert.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Cancel, null)); + alert.AddAction (UIAlertAction.Create ("Reset & Exit", UIAlertActionStyle.Destructive, _ => { + NSUserDefaults.StandardUserDefaults.RemoveObject (SelectedModeKey); + NSUserDefaults.StandardUserDefaults.Synchronize (); + + // Exit the app (user must manually restart) + var exitAlert = UIAlertController.Create ( + "Mode Reset", + "Please restart the app to select a new mode.", + UIAlertControllerStyle.Alert + ); + exitAlert.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Default, _ => { + // iOS doesn't allow programmatic exit, but we can show this message + })); + viewController.PresentViewController (exitAlert, true, null); + })); + viewController.PresentViewController (alert, true, null); }; viewController.View.AddSubview (statusLabel); - viewController.View.AddSubview (tokenButton); + if (tokenButton is not null) { + viewController.View.AddSubview (tokenButton); + } + viewController.View.AddSubview (resetButton); - NSLayoutConstraint.ActivateConstraints (new [] { + var constraints = new List { statusLabel.LeadingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.LeadingAnchor, 24), statusLabel.TrailingAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TrailingAnchor, -24), - statusLabel.TopAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TopAnchor, 120), - tokenButton.TopAnchor.ConstraintEqualTo (statusLabel.BottomAnchor, 24), - tokenButton.CenterXAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.CenterXAnchor) - }); + statusLabel.TopAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.TopAnchor, 80) + }; + + if (tokenButton is not null) { + constraints.AddRange (new [] { + tokenButton.TopAnchor.ConstraintEqualTo (statusLabel.BottomAnchor, 32), + tokenButton.CenterXAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.CenterXAnchor) + }); + constraints.Add (resetButton.TopAnchor.ConstraintEqualTo (tokenButton.BottomAnchor, 80)); + } else { + constraints.Add (resetButton.TopAnchor.ConstraintEqualTo (statusLabel.BottomAnchor, 80)); + } + + constraints.Add (resetButton.CenterXAnchor.ConstraintEqualTo (viewController.View.SafeAreaLayoutGuide.CenterXAnchor)); + + NSLayoutConstraint.ActivateConstraints (constraints.ToArray ()); return viewController; }