Skip to content

Commit f044e14

Browse files
authored
Merge pull request #2 from Kapusch/feature/facebook-share-and-release-policy
Add Facebook Share and adopt master-only releases
2 parents cbb1cea + 5d1f489 commit f044e14

20 files changed

Lines changed: 493 additions & 107 deletions

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ jobs:
6767
required = [
6868
"buildTransitive/Kapusch.Facebook.iOS.targets",
6969
"kfb.xcframework/Info.plist",
70+
"kfbshare.xcframework/Info.plist",
7071
"fb/FBAEMKit.xcframework/Info.plist",
7172
"fb/FBSDKCoreKit.xcframework/Info.plist",
7273
"fb/FBSDKCoreKit_Basics.xcframework/Info.plist",
73-
"fb/FBSDKGamingServicesKit.xcframework/Info.plist",
7474
"fb/FBSDKLoginKit.xcframework/Info.plist",
7575
"fb/FBSDKShareKit.xcframework/Info.plist",
7676
]
@@ -87,6 +87,10 @@ jobs:
8787
print("ERROR: wrapper appears flattened (found 'Info.plist' at package root).")
8888
sys.exit(1)
8989
90+
if any(name.startswith("fb/FBSDKGamingServicesKit.xcframework/") for name in names):
91+
print("ERROR: GamingServicesKit must not be packaged.")
92+
sys.exit(1)
93+
9094
print("OK: nupkg layout looks correct.")
9195
PY
9296

.github/workflows/publish.yml

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ jobs:
3232
shell: bash
3333
run: |
3434
REF="${{ github.ref }}"
35-
EVENT="${{ github.event_name }}"
3635
MANUAL_VERSION="${{ github.event.inputs.manual_version }}"
3736
CSPROJ="src/Kapusch.FacebookApisForiOSComponents/Kapusch.FacebookApisForiOSComponents.csproj"
3837
BASE_VERSION=$(grep -oE '<Version>[^<]+' "$CSPROJ" | head -n 1 | sed 's/<Version>//' || echo "0.1.0")
@@ -52,27 +51,14 @@ jobs:
5251
fi
5352
5453
if [[ "$PUBLISH_TARGET" == "nuget" ]]; then
55-
git fetch origin +refs/heads/*:refs/remotes/origin/*
56-
TAGGED_SHA="${{ github.sha }}"
57-
CONTAINING_BRANCHES=$(git for-each-ref --format='%(refname:short)' refs/remotes/origin --contains "$TAGGED_SHA")
58-
59-
ON_MASTER="false"
60-
ON_RELEASE="false"
61-
while IFS= read -r branch; do
62-
[[ "$branch" == "origin/master" ]] && ON_MASTER="true"
63-
[[ "$branch" == origin/release/* ]] && ON_RELEASE="true"
64-
done <<< "$CONTAINING_BRANCHES"
65-
66-
if [[ "$VERSION" == *-* ]]; then
67-
if [[ "$ON_RELEASE" != "true" ]]; then
68-
echo "ERROR: Pre-release version $VERSION must be on origin/release/*"
69-
exit 1
70-
fi
71-
else
72-
if [[ "$ON_MASTER" != "true" ]]; then
73-
echo "ERROR: Stable version $VERSION must be on origin/master"
74-
exit 1
75-
fi
54+
git fetch origin master
55+
if ! git merge-base --is-ancestor "${{ github.sha }}" origin/master; then
56+
echo "ERROR: NuGet.org releases must be reachable from origin/master."
57+
exit 1
58+
fi
59+
if [[ -n "$MANUAL_VERSION" && "$REF" != "refs/heads/master" ]]; then
60+
echo "ERROR: Manual NuGet.org releases must be dispatched from master."
61+
exit 1
7662
fi
7763
fi
7864
@@ -136,10 +122,10 @@ jobs:
136122
required = [
137123
"buildTransitive/Kapusch.Facebook.iOS.targets",
138124
"kfb.xcframework/Info.plist",
125+
"kfbshare.xcframework/Info.plist",
139126
"fb/FBAEMKit.xcframework/Info.plist",
140127
"fb/FBSDKCoreKit.xcframework/Info.plist",
141128
"fb/FBSDKCoreKit_Basics.xcframework/Info.plist",
142-
"fb/FBSDKGamingServicesKit.xcframework/Info.plist",
143129
"fb/FBSDKLoginKit.xcframework/Info.plist",
144130
"fb/FBSDKShareKit.xcframework/Info.plist",
145131
]
@@ -155,6 +141,10 @@ jobs:
155141
print("ERROR: wrapper appears flattened (found 'Info.plist' at package root).")
156142
sys.exit(1)
157143
144+
if any(name.startswith("fb/FBSDKGamingServicesKit.xcframework/") for name in names):
145+
print("ERROR: GamingServicesKit must not be packaged.")
146+
sys.exit(1)
147+
158148
print("OK: nupkg layout looks correct.")
159149
PY
160150

AGENTS.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Kapusch.FacebookApisForiOSComponents — AI Working Agreement
22

33
## Goals
4-
- Produce a reproducible iOS NuGet package for Facebook Login interop.
4+
- Produce a reproducible iOS NuGet package for selectable Facebook Login and Share interop.
55
- Do not commit secrets.
66

77
## Packaging constraints
@@ -19,3 +19,9 @@
1919
## Safety
2020
- Do not add new dependency ingestion paths without documenting them in `README.md`.
2121
- Do not commit real app ids/secrets.
22+
23+
## Branches and releases
24+
- `master` is the only long-lived branch and the source of every NuGet.org release.
25+
- Implement changes on short-lived branches and target `master` through a PR. Never implement directly on `release/*`.
26+
- Both stable (`vX.Y.Z`) and prerelease (`vX.Y.Z-rc.N`) tags must reference commits reachable from `origin/master`.
27+
- Manual runs without a version publish previews to GitHub Packages. See `Docs/Release.md` for the complete contract.

CONTRIBUTING.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ Pack the NuGet:
3232
## Pull requests
3333

3434
- Keep PRs focused and well-scoped.
35+
- Branch from `master` and target `master`; this repository does not use long-lived `release/*` branches.
3536
- Do not commit secrets.
3637
- If you update the Facebook SDK version, update `Package.swift` and `Package.resolved` together.
3738

39+
See `Docs/Release.md` before changing versions, tags, or publishing workflows.
40+
3841
## License
3942

4043
By contributing, you agree that your contributions will be licensed under the repository license (MIT).

Docs/Integration.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,22 @@ Call the interop hooks in your `AppDelegate`:
2828
- On launch: `NativeFacebookLogin.Initialize(app, options)`
2929
- On URL open: `NativeFacebookLogin.HandleOpenUrl(app, url, options)`
3030

31-
## 3) Limited Login
31+
These hooks apply to `KapuschFacebookFeatures=Login`. For Share-only builds,
32+
disable Meta automatic initialization and call
33+
`NativeFacebookShare.ConfigureAndInitialize(app.Handle, trackingAllowed)` only
34+
after the ATT decision, immediately before the first share. Then call
35+
`NativeFacebookShare.SharePhotoAsync(...)`; no caption is accepted.
36+
37+
## 3) Feature selection
38+
39+
- `Login` (default): Login wrapper and LoginKit.
40+
- `Share`: photo-share wrapper and ShareKit.
41+
- `Login;Share`: both managed/native entry points.
42+
43+
At SDK 18.0.2, ShareKit's CoreKit dependency requires FBAEMKit. Treat this as a
44+
privacy-review blocker if the consumer's artifact policy excludes FBAEMKit.
45+
46+
## 4) Limited Login
3247

3348
For Limited Login, pass:
3449
- `FacebookTrackingMode.Limited`
@@ -38,7 +53,7 @@ The result can contain:
3853
- `AuthenticationToken`
3954
- `Nonce`
4055

41-
## 4) Secrets policy
56+
## 5) Secrets policy
4257

4358
Do not commit real values in this repo.
4459
Use templates and `.gitignore`d local files for any sample app configuration.

Docs/Release.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Release workflow
2+
3+
`master` is the only long-lived branch. Feature work uses short-lived branches and pull requests targeting `master`; this repository does not create `release/*` branches.
4+
5+
## Channels
6+
7+
- Manual workflow run without `manual_version`: build a preview package and publish it to GitHub Packages.
8+
- `vX.Y.Z-rc.N` tag reachable from `origin/master`: publish that prerelease to NuGet.org.
9+
- `vX.Y.Z` tag reachable from `origin/master`: publish that stable version to NuGet.org.
10+
- Manual workflow run with `manual_version`: publish to NuGet.org only when the workflow runs from `master`.
11+
12+
NuGet versions and Git tags are immutable. Query the official NuGet index before publishing and never move or recreate an existing tag.
13+
14+
## Release sequence
15+
16+
1. Fetch `origin`, start a short-lived branch from `origin/master`, and verify the worktree is clean.
17+
2. Build the Swift wrappers, collect the locked Facebook xcframeworks, pack the NuGet and validate its module selection.
18+
3. Open a PR to `master` and require CI to pass.
19+
4. Merge and fetch the resulting `origin/master` commit.
20+
5. Create the RC or stable tag on that exact commit and push only the new tag.
21+
6. Verify the publish workflow and the resulting NuGet package before updating consumers.
22+
23+
Do not delete historical tags. Delete a temporary branch only after every retained commit is reachable from `origin/master`.

README.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# FacebookApisForiOSComponents
22

3-
Public OSS repository that packages **Facebook Login for iOS** into a consumable .NET NuGet.
3+
Public OSS repository that packages selected Facebook iOS features into a consumable .NET NuGet.
44

55
## Package
66

@@ -9,10 +9,18 @@ Public OSS repository that packages **Facebook Login for iOS** into a consumable
99
## What this repo ships
1010

1111
A NuGet package that:
12-
- provides a small managed API for **Facebook Login (iOS)**, and
12+
- provides managed APIs for **Facebook Login** and **Facebook photo sharing**, and
1313
- redistributes the required **Facebook iOS SDK xcframeworks** inside the `.nupkg` (classic/native binding packaging),
1414
- injects the xcframeworks into consuming apps via `buildTransitive` `NativeReference` items.
1515

16+
Select features with `KapuschFacebookFeatures=Login`, `Share`, or `Login;Share`.
17+
The default remains `Login` for compatibility.
18+
19+
Facebook iOS SDK 18.0.2 links `FBSDKCoreKit` to `FBAEMKit` non-weakly. Therefore
20+
`Share` currently includes `ShareKit`, `CoreKit`, `CoreKit_Basics` and `FBAEMKit`.
21+
A consumer that forbids `FBAEMKit` must block Store delivery; this repository
22+
does not strip or conceal the dependency.
23+
1624
## Third-party licenses
1725

1826
See `THIRD_PARTY_NOTICES.md`.
@@ -21,6 +29,7 @@ See `THIRD_PARTY_NOTICES.md`.
2129

2230
- Formatting: `Docs/Formatting.md`
2331
- Source mode: `Docs/SourceMode.md`
32+
- Release workflow: `Docs/Release.md`
2433
- Samples: `samples/README.md`
2534

2635
## Build (local)
@@ -49,22 +58,13 @@ Pack the NuGet:
4958
- PR CI is build-only.
5059
- Publishing is handled by `.github/workflows/publish.yml` with channel routing:
5160
- tag `vX.Y.Z` on `master` -> NuGet.org (stable)
52-
- tag `vX.Y.Z-rc.N` on `release/*` -> NuGet.org (pre-release)
61+
- tag `vX.Y.Z-rc.N` on `master` -> NuGet.org (pre-release)
5362
- non-tag runs (`workflow_dispatch`) -> GitHub Packages (`X.Y.Z-preview.<run>.<sha>`)
54-
- `workflow_dispatch` with `manual_version` -> NuGet.org (forced version)
63+
- `workflow_dispatch` on `master` with `manual_version` -> NuGet.org (forced version)
5564
- NuGet.org publishing uses NuGet Trusted Publishing (OIDC via `NuGet/login@v1`), no long-lived NuGet API key.
5665

5766
### Required GitHub secret
5867

5968
- `NUGET_USER`: your nuget.org profile username (not email), used by `NuGet/login@v1`.
6069

61-
## Release examples
62-
63-
- Pre-release candidate from a release branch:
64-
- `git checkout release/1.0.0`
65-
- `git tag v1.0.0-rc.1`
66-
- `git push origin v1.0.0-rc.1`
67-
- Stable release from master:
68-
- `git checkout master`
69-
- `git tag v1.0.0`
70-
- `git push origin v1.0.0`
70+
See `Docs/Release.md` for the validated release sequence. Historical tags remain immutable even when obsolete branches are deleted.

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
33
"version": "10.0.100",
4-
"rollForward": "patch"
4+
"rollForward": "latestFeature"
55
}
66
}

src/Kapusch.FacebookApisForiOSComponents/Facebook/NativeFacebookLogin.iOS.cs

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@ namespace Kapusch.Facebook.iOS;
55

66
public static unsafe class NativeFacebookLogin
77
{
8-
private const string LibraryName = "__Internal";
9-
108
public static void Initialize(IntPtr uiApplicationHandle, IntPtr launchOptionsHandle)
119
{
1210
if (uiApplicationHandle == IntPtr.Zero)
1311
return;
1412

1513
try
1614
{
17-
KfiFacebookInitialize(
15+
ResolveInitialize()(
1816
uiApplicationHandle,
1917
launchOptionsHandle
2018
);
@@ -36,11 +34,11 @@ IntPtr optionsHandle
3634

3735
try
3836
{
39-
return KfiFacebookHandleOpenUrl(
37+
return ResolveHandleOpenUrl()(
4038
uiApplicationHandle,
4139
nsUrlHandle,
4240
optionsHandle
43-
);
41+
) != 0;
4442
}
4543
catch
4644
{
@@ -68,13 +66,29 @@ public static Task<NativeFacebookSignInResult> SignInAsync(
6866
var gch = GCHandle.Alloc(tcs);
6967
var context = GCHandle.ToIntPtr(gch);
7068

71-
KfiFacebookSignInStart(
72-
presentingViewControllerHandle,
73-
(int)trackingMode,
74-
rawNonce,
75-
&KfiFacebookCallback,
76-
context
77-
);
69+
var noncePointer = string.IsNullOrEmpty(rawNonce)
70+
? IntPtr.Zero
71+
: Marshal.StringToCoTaskMemUTF8(rawNonce);
72+
try
73+
{
74+
ResolveSignInStart()(
75+
presentingViewControllerHandle,
76+
(int)trackingMode,
77+
noncePointer,
78+
&KfiFacebookCallback,
79+
context
80+
);
81+
}
82+
catch
83+
{
84+
gch.Free();
85+
throw;
86+
}
87+
finally
88+
{
89+
if (noncePointer != IntPtr.Zero)
90+
Marshal.FreeCoTaskMem(noncePointer);
91+
}
7892

7993
_ = cancellationToken.Register(() =>
8094
tcs.TrySetResult(new NativeFacebookSignInResult(NativeSignInStatus.Cancelled))
@@ -87,7 +101,7 @@ public static void SignOut()
87101
{
88102
try
89103
{
90-
KfiFacebookSignOut();
104+
ResolveSignOut()();
91105
}
92106
catch
93107
{
@@ -130,35 +144,32 @@ IntPtr context
130144
}
131145
}
132146

133-
[DllImport(LibraryName, EntryPoint = "kfb_facebook_initialize")]
134-
private static extern void KfiFacebookInitialize(IntPtr uiApplication, IntPtr launchOptions);
135-
136-
[DllImport(LibraryName, EntryPoint = "kfb_facebook_handle_open_url")]
137-
[return: MarshalAs(UnmanagedType.I1)]
138-
private static extern bool KfiFacebookHandleOpenUrl(
139-
IntPtr uiApplication,
140-
IntPtr nsUrl,
141-
IntPtr options
142-
);
143-
144-
[DllImport(LibraryName, EntryPoint = "kfb_facebook_signin_start")]
145-
private static extern void KfiFacebookSignInStart(
146-
IntPtr presentingViewController,
147-
int trackingMode,
148-
[MarshalAs(UnmanagedType.LPUTF8Str)] string? rawNonce,
149-
delegate* unmanaged[Cdecl]<
150-
int,
151-
IntPtr,
152-
IntPtr,
153-
IntPtr,
154-
IntPtr,
147+
private static IntPtr Resolve(string symbol) =>
148+
NativeLibrary.GetExport(NativeLibrary.GetMainProgramHandle(), symbol);
149+
150+
private static delegate* unmanaged[Cdecl]<IntPtr, IntPtr, void> ResolveInitialize() =>
151+
(delegate* unmanaged[Cdecl]<IntPtr, IntPtr, void>)Resolve("kfb_facebook_initialize");
152+
153+
private static delegate* unmanaged[Cdecl]<IntPtr, IntPtr, IntPtr, byte> ResolveHandleOpenUrl() =>
154+
(delegate* unmanaged[Cdecl]<IntPtr, IntPtr, IntPtr, byte>)Resolve(
155+
"kfb_facebook_handle_open_url"
156+
);
157+
158+
private static delegate* unmanaged[Cdecl]<
159+
IntPtr,
160+
int,
161+
IntPtr,
162+
delegate* unmanaged[Cdecl]<int, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, void>,
163+
IntPtr,
164+
void> ResolveSignInStart() =>
165+
(delegate* unmanaged[Cdecl]<
155166
IntPtr,
167+
int,
156168
IntPtr,
169+
delegate* unmanaged[Cdecl]<int, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, void>,
157170
IntPtr,
158-
void> callback,
159-
IntPtr context
160-
);
171+
void>)Resolve("kfb_facebook_signin_start");
161172

162-
[DllImport(LibraryName, EntryPoint = "kfb_facebook_signout")]
163-
private static extern void KfiFacebookSignOut();
173+
private static delegate* unmanaged[Cdecl]<void> ResolveSignOut() =>
174+
(delegate* unmanaged[Cdecl]<void>)Resolve("kfb_facebook_signout");
164175
}

0 commit comments

Comments
 (0)