The Facebook SDKs for Android and iOS give a mobile app three things: Facebook Login, native sharing dialogs, and App Events for measurement and ad optimization. You add the SDK through Gradle or Swift Package Manager, drop your App ID and Client Token into the platform config, and initialize once at launch. Everything after that is a question of which permissions you request and how carefully you handle Apple’s tracking rules.
com.facebook.android:facebook-android-sdk:latest.release to your app module, put facebook_app_id and facebook_client_token in strings.xml, and point the application manifest at both string resources. On iOS pull FBSDKCoreKit, FBSDKLoginKit and FBSDKShareKit from CocoaPods or SPM, then add FacebookAppID, FacebookClientToken, FacebookDisplayName and your fb<APP_ID> URL scheme to Info.plist. Request the ATT prompt before logging revenue events on iOS, and ship the SDK version that carries a privacy manifest.Meta ships the mobile SDKs as a set of kits rather than one monolith, which matters because pulling the full artifact drags in ad measurement code you may not want in a build that only needs login. Below is what each piece does, how to wire it on both platforms, and the privacy plumbing that decides whether your install and purchase events are actually usable for ad optimization.
What each SDK component does
Both platforms expose roughly the same surface with different naming. On iOS the components are separate Swift packages and pods. On Android they are separate Maven artifacts under the com.facebook.android group. Pick the narrowest set that covers your feature list.
| Capability | iOS component | Android artifact | Needs App Review |
|---|---|---|---|
| Core init, App Events, settings | FBSDKCoreKit | facebook-core | No |
| Facebook Login | FBSDKLoginKit | facebook-login | Only beyond public_profile |
| Share sheet and dialogs | FBSDKShareKit | facebook-share | No for the native dialog |
| Everything at once | FacebookSDK umbrella | facebook-android-sdk | Depends on usage |
The Client Token is not optional any more. Since version 13 of both SDKs, calls to the Graph API from a mobile client require it, and you find it under App Dashboard, then Settings, then Advanced, in the Security block. It is not a secret in the way your App Secret is, but it still belongs in config rather than hardcoded in a public repository.
Android setup with Gradle
Add the Maven Central repository if your project does not already have it, then declare the dependency in the app module build file. Meta publishes a latest.release alias, which is convenient for a spike and a bad idea for a production build. Pin an explicit version and bump it deliberately.
// app/build.gradle.kts
dependencies {
implementation("com.facebook.android:facebook-login:latest.release")
implementation("com.facebook.android:facebook-share:latest.release")
}Next, put the identifiers in string resources so they can be swapped per build flavor, and wire them into the manifest.
<!-- app/src/main/res/values/strings.xml -->
<string name="facebook_app_id">YOUR_APP_ID</string>
<string name="facebook_client_token">YOUR_CLIENT_TOKEN</string>
<string name="fb_login_protocol_scheme">fbYOUR_APP_ID</string>
<!-- AndroidManifest.xml, inside <application> -->
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id"/>
<meta-data android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token"/>You also need android.permission.INTERNET declared. Modern SDK builds add the Advertising ID permission for you, which is worth knowing before a Play Console data safety review asks why it appeared.
Login itself runs through LoginManager and a CallbackManager that you forward results into from onActivityResult. If Facebook is one identity provider among several in your product, our guide to implementing single sign on with Facebook covers how to reconcile it with an existing account model.
val callbackManager = CallbackManager.Factory.create()
LoginManager.getInstance().registerCallback(
callbackManager,
object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult) {
val token = result.accessToken.token
sendToBackend(token) // verify server side, never trust the client
}
override fun onCancel() { /* user backed out */ }
override fun onError(error: FacebookException) { logFailure(error) }
}
)
LoginManager.getInstance()
.logInWithReadPermissions(this, listOf("public_profile", "email"))iOS setup with CocoaPods or Swift Package Manager
For CocoaPods, list only the kits you use. For Swift Package Manager, add https://github.com/facebook/facebook-ios-sdk as a package dependency and select the same product names.
# Podfile
platform :ios, '15.0'
target 'MyApp' do
use_frameworks!
pod 'FBSDKCoreKit'
pod 'FBSDKLoginKit'
pod 'FBSDKShareKit'
endInfo.plist carries the identity keys plus the URL scheme that lets the Facebook app hand control back to yours after a login round trip.
<key>FacebookAppID</key><string>YOUR_APP_ID</string>
<key>FacebookClientToken</key><string>YOUR_CLIENT_TOKEN</string>
<key>FacebookDisplayName</key><string>My App</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array><string>fbYOUR_APP_ID</string></array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
</array>Initialize in the app delegate and forward the incoming URL so login completes.
import FBSDKCoreKit
func application(_ app: UIApplication,
didFinishLaunchingWithOptions opts: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
ApplicationDelegate.shared.application(app, didFinishLaunchingWithOptions: opts)
return true
}
func application(_ app: UIApplication, open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return ApplicationDelegate.shared.application(app, open: url, options: options)
}App Events and why they decide your ad performance
App Events are the measurement layer. The SDK automatically logs app install, app launch and in app purchase unless you disable it, and you add your own events for the moments that matter to your funnel.
// Swift
AppEvents.shared.logEvent(AppEvents.Name("completed_onboarding"))
AppEvents.shared.logPurchase(amount: 9.99, currency: "USD")
// Kotlin
val logger = AppEventsLogger.newLogger(this)
logger.logEvent("completed_onboarding")To turn automatic logging off on iOS, set FacebookAutoLogAppEventsEnabled to false in Info.plist, or flip Settings.shared.isAutoLogAppEventsEnabled at runtime once you know the user’s consent state. Do that before the SDK sends anything if you operate under GDPR or a state privacy law that requires prior consent.
Events you never register in Events Manager still arrive, but they cannot be used as an optimization target until you configure them. If you plan to run install or purchase campaigns, wire the event names first and check them against what you set up when you set up a Facebook ad campaign.
App Tracking Transparency, SKAdNetwork and the privacy manifest
On iOS the tracking prompt is the single biggest variable in your measurement quality. Apple requires the App Tracking Transparency prompt before your app reads the identifier for advertisers or shares data with Meta for cross app tracking. Meta reads the authorization status and restricts how it uses events from devices that declined.
import AppTrackingTransparency
import FBSDKCoreKit
ATTrackingManager.requestTrackingAuthorization { status in
// On iOS 14.5 through 16.x the SDK exposed an explicit flag.
// The setter is deprecated in recent SDK majors; newer versions
// read ATTrackingManager.trackingAuthorizationStatus directly.
Settings.shared.isAdvertiserTrackingEnabled = (status == .authorized)
}Meta’s guidance is explicit that if the advertiser tracking signal is missing on iOS 14.5 and later, it may restrict its use of that event. Practically, that means opted out installs flow through SKAdNetwork rather than through identifier based attribution, and you see aggregated postbacks with coarse conversion values instead of user level results.
Apple also requires a privacy manifest for third party SDKs that reach the App Store. Meta ships PrivacyInfo.xcprivacy inside recent SDK versions, covering the data the SDK collects by default and the tracking domains it contacts. If your archive fails validation with a missing privacy manifest error, the fix is almost always to update to a current SDK release rather than to author a manifest yourself. Anything your own code collects still belongs in your app level manifest.
Troubleshooting
Login returns immediately with a cancel and no error. The URL scheme is wrong. It must be the literal string fb followed by your numeric App ID, with no spaces, and it must appear in CFBundleURLSchemes. On Android, check that the FacebookActivity and CustomTabActivity entries generated by the manifest merger survived a manifest override.
Graph calls fail with an error about a missing client token. The Client Token entry in the manifest is absent or points at an empty string resource. Print the resolved value at launch in a debug build and confirm it is not the placeholder.
App Events show up in Events Manager but never in ad reporting. The event is being logged before consent is resolved, or it was never registered as a standard or custom event you can optimize toward. Check the testing tab in Events Manager with a device added as a test device.
Release builds crash on login while debug builds work. The key hash for the release keystore is not registered in the App Dashboard. Generate it from the signing keystore and add it under Settings, then Basic, then Android platform key hashes.
App Store Connect rejects the binary for a missing usage description. If you call ATT you must ship NSUserTrackingUsageDescription with a plain sentence explaining the benefit to the user. An empty or vague string draws a rejection on its own.
Frequently asked questions
Do I need App Review to ship Facebook Login?
Not for public_profile, which every app receives automatically. Any additional scope, including email, needs Advanced Access before it works for people who do not hold a role on your app. Build with test users first, then submit a screencast of the real login flow.
Can I use the SDK without Facebook Login?
Yes. FBSDKCoreKit and the Android core artifact work on their own for App Events and measurement. Many advertisers integrate only the core piece so install and purchase events reach Meta, and keep their own authentication stack untouched.
What happens if a user declines the ATT prompt?
Your app keeps working. Meta receives the events but restricts how it uses them, so attribution for that user comes through SKAdNetwork postbacks rather than device level matching. Expect conversion counts in Ads Manager to sit below what your own analytics report.
Should I pin the SDK version or use latest.release?
Pin it. The latest.release alias means a fresh build can pull a new major version without a code change, which is how a privacy manifest change or a deprecated setter turns into a surprise failure in a release branch. Bump the pin on purpose and test.
Does the SDK work with React Native or Flutter?
Through community and Meta maintained wrappers, yes, but the underlying native setup is identical. You still add the App ID, Client Token, URL scheme and privacy manifest at the native layer, so the platform config sections above apply either way.
The bottom line
Getting the Facebook SDKs into an app is a config exercise more than a coding one. Add the right artifacts, put the App ID and Client Token where each platform expects them, register the URL scheme, and forward the app delegate callbacks. That takes an afternoon.
The part that takes longer is measurement hygiene. Decide when you fire the ATT prompt, decide which events matter and rank them for SKAdNetwork, keep the SDK current so the privacy manifest stays valid, and validate every client token on your own server. Get that right and the ad platform has something real to optimize against. Get it wrong and you ship an SDK that costs you binary size and returns nothing. Meta’s iOS SDK documentation is the reference to check whenever a major version lands.
