تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
يؤدي استخدام ميزة "قلب التطبيقات" (App Flip) المستنِد إلى بروتوكول OAuth إلى فتح تطبيق iOS من أحد تطبيقات Google.
لمساعدة مستخدم تطبيق Google على ربط حسابه بسهولة أكبر. عليك إجراء
تغييرات طفيفة على رمز تطبيق iOS لتنفيذ هذه الميزة.
ستتعرّف في هذا المستند على كيفية تعديل تطبيق iOS لدعم ميزة App Flip.
تجربة النموذج
نموذج تطبيق ميزة "قلب التطبيق"
تعرض عملية دمج لربط الحساب على نظام iOS يتوافق مع App Flip.
يمكنك استخدام هذا التطبيق للتحقّق من طريقة الردّ على رسالة App Flip واردة عامة.
من تطبيقات الأجهزة الجوّالة من Google.
تم ضبط نموذج التطبيق مسبقًا للدمج مع أداة اختبار قلب التطبيق).
iOS،
الذي يمكنك استخدامه للتحقّق من تكامل تطبيق iOS مع ميزة App Flip قبل
يمكنك إعداد ربط الحساب بـ Google. يحاكي هذا التطبيق الرابط العام.
يتم تشغيلها بواسطة تطبيقات Google المتوافقة مع الأجهزة الجوّالة عند تفعيل ميزة "قلب التطبيقات".
آلية العمل
في ما يلي خطوات العملية التي يتّخذها تطبيق Google وتطبيقك عند
يحدث قلب التطبيق:
يحاول تطبيق Google فتح الرابط العام لتطبيقك. من الممكن
افتح التطبيق إذا كان مثبّتًا على جهاز المستخدم ومرتبطًا
الرابط العام. راجِع إتاحة الروابط العامة لمعرفة التفاصيل.
يتحقّق تطبيقك من ترميز المَعلمتَين client_id وredirect_uri.
في عنوان URL الوارد مع الرابط العام المتوقع لـ Google.
يطلب تطبيقك رمز تفويض من خادم OAuth2. في النهاية
يعرض التطبيق رمز تفويض أو خطأ
تطبيق Google. وللقيام بذلك، يتم فتح رابط Google العام مع ملحق
المَعلمات لرمز التفويض أو الخطأ.
يعالج تطبيق Google الرابط العام الوارد من Google ويستمر في
بقية التدفق. إذا تم تقديم رمز تفويض، سيتم
على الفور. يحدث تبادل الرموز المميزة بين الخوادم، بالطريقة نفسها
وهو ما يحدث في تدفق ربط OAuth المستند إلى المتصفح. إذا كان رمز الخطأ
يستمر تدفق الربط مع الخيارات البديلة.
تعديل تطبيق iOS لدعم ميزة "قلب التطبيقات"
لإتاحة ميزة "قلب التطبيقات"، عليك إجراء التغييرات التالية على الرمز في تطبيق iOS:
استخدِم الاسم المعرِّف "NSUserActivityTypeBrowsingWeb" في ميزة "تفويض التطبيقات".
التقاط المَعلمتَين redirect_uri وstate من عنوان URL لاستخدامهما لاحقًا
بعد نجاح التفويض، اطلب معرّف الموارد المنتظم (URI) لإعادة التوجيه مع الحصول على الإذن
الرمز. استخدِم نموذج الرمز البرمجي التالي:
funcreturnAuthCode(code:String,state:String,redirectUri:String){varredirectURL=URL(string:redirectUri)varcomponents=URLComponents(url:redirectURL,resolvingAgainstBaseURL:false)// Return the authorization code and original stateletparamAuthCode=URLQueryItem(name:"code",value:code)letparamState=URLQueryItem(name:"state",value:state)components?.queryItems=[paramAuthCode,paramState]ifletresultURL=components?.url{UIApplication.shared.open(resultURL,options:[UIApplicationOpenURLOptionUniversalLinksOnly:true],completionHandler:nil)}}
إذا حدث خطأ، أرفِق نتيجة خطأ بمعرّف الموارد المنتظم (URI) لإعادة التوجيه بدلاً من ذلك.
استخدِم نموذج الرمز البرمجي التالي:
funcreturnError(redirectUri:String){varredirectURL=URL(string:redirectUri)varcomponents=URLComponents(url:redirectURL,resolvingAgainstBaseURL:false)// Return the authorization code and original stateletparamError=URLQueryItem(name:"error",value:"invalid_request")letparamDescription=URLQueryItem(name:"error_description",value:"Invalid Request")components?.queryItems=[paramError,paramDescription]ifletresultURL=components?.url{UIApplication.shared.open(resultURL,options:[UIApplicationOpenURLOptionUniversalLinksOnly:true],completionHandler:nil)}}
مَعلمات طلب البحث للرابط العام لتطبيقك
عند فتح هذا التطبيق من خلال تطبيق Google، يتضمّن الرابط العام لتطبيقك ما يلي:
مَعلمات طلب البحث:
client_id (String): Google client_id المسجَّل ضمن تطبيقك.
scope (List of String): قائمة بالنطاقات المفصولة بمسافات مطلوبة
state (String): رقم تعريف غير تستخدمه Google للتحقّق من أنّ التفويض
هي استجابة لطلب Google الصادر.
redirect_uri (String): رابط Google العام. "قلب" معرّف الموارد المنتظم (URI) المطلوب فتحه
تطبيق Google واجتياز النتائج
مَعلمات طلب البحث لرابط Google العام
المَعلمات المستخدَمة عند عرض نتيجة التفويض بنجاح:
code (String): قيمة رمز التفويض، في حال توفّرها.
state (String): القيمة الدقيقة التي يتم تلقّيها من الرابط العام الوارد
المَعلمات التي يتم استخدامها عند عرض نتيجة التفويض بشكل غير ناجح:
error (String)، مع القيم التالية:
cancelled: خطأ يمكن إصلاحه. سيحاول تطبيق Google استخدام الحساب
باستخدام عنوان URL للتفويض. بعض الأمثلة هي فشل المستخدم
لتسجيل الدخول، أو عدم اتصال الجهاز بالإنترنت أو انتهاء مهلة الاتصال.
unrecoverable: خطأ غير قابل للإصلاح. على سبيل المثال، يحاول المستخدم الربط بحساب غير مفعَّل.سيلغي تطبيق Google ربط الحساب.
invalid_request: معلَمات الطلب غير صالحة أو غير متوفّرة يمكن إصلاح هذا الخطأ. سيحاول تطبيق Google ربط الحسابات باستخدام عنوان URL للتفويض.
access_denied: يرفض المستخدم طلب الموافقة. هذا خطأ لا يمكن إصلاحه؛ يلغي تطبيق Google الربط.
error_description (String، اختياري): رسالة خطأ سهلة الاستخدام
بالنسبة إلى جميع أنواع الأخطاء، يجب عرض بيانات الاستجابة على
REDIRECT_URI للتأكّد من ترتيب الإجراء الاحتياطي المناسب.
تعديل نقطة نهاية التفويض لإتاحة استخدام ميزة "قلب التطبيقات"
يمكنك ضبط النظام الأساسي لقبول الطلبات باستخدام عناوين URL لإعادة التوجيه لميزة App Flip من Google:
تأكّد من أنّ client_id وعنوان URL المحدَّدين من خلال المَعلمة redirect_uri
تتطابق مع القيم المتوقعة عند تلقي طلب. إذا كانت عملية التحقّق من العميل
الأخطاء، يمكنك إرجاع الخطأ invalid_request إلى redirect_uri.
تاريخ التعديل الأخير: 2025-07-25 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","easyToUnderstand","thumb-up"],["ساعَدني المحتوى في حلّ مشكلتي.","solvedMyProblem","thumb-up"],["غير ذلك","otherUp","thumb-up"]],[["لا يحتوي على المعلومات التي أحتاج إليها.","missingTheInformationINeed","thumb-down"],["الخطوات معقدة للغاية / كثيرة جدًا.","tooComplicatedTooManySteps","thumb-down"],["المحتوى قديم.","outOfDate","thumb-down"],["ثمة مشكلة في الترجمة.","translationIssue","thumb-down"],["مشكلة في العيّنات / التعليمات البرمجية","samplesCodeIssue","thumb-down"],["غير ذلك","otherDown","thumb-down"]],["تاريخ التعديل الأخير: 2025-07-25 (حسب التوقيت العالمي المتفَّق عليه)"],[[["\u003cp\u003eOAuth-based App Flip linking simplifies account linking for Google app users by enabling them to seamlessly open your iOS app for authorization.\u003c/p\u003e\n"],["\u003cp\u003eTo support App Flip, you need to modify your iOS app to handle universal links, validate incoming parameters, and return authorization codes or errors to the Google app.\u003c/p\u003e\n"],["\u003cp\u003eYour authorization endpoint must be configured to accept Google's App Flip redirect URLs and perform client verification for incoming requests.\u003c/p\u003e\n"],["\u003cp\u003eThe App Flip sample app and test tool provide a practical demonstration and verification environment for your iOS app's integration with App Flip.\u003c/p\u003e\n"]]],[],null,["OAuth-based App Flip linking (App Flip) opens your iOS app from a Google app\nto help the Google app user link their account more easily. You need to make\nminor code changes to your iOS app to implement this feature.\n\nIn this document, you learn how to modify your iOS app to support App Flip.\n\nTry the sample\n\nThe App Flip [sample app](https://github.com/googlesamples/identity-appflip-ios)\ndemonstrates an account linking integration on iOS that's App Flip-compatible.\nYou can use this app to verify how to respond to an incoming App Flip universal\nlink from Google mobile apps.\n\nThe sample app is preconfigured to integrate with the [App Flip Test Tool for\niOS](https://github.com/googlesamples/identity-appflip-tester-ios),\nwhich you can use to verify your iOS app's integration with App Flip before\nyou configure account linking with Google. This app simulates the universal link\ntriggered by Google mobile apps when App Flip is enabled.\n\nHow it works\n\nThe following are the flow steps that the Google app and your app take when\nApp Flip occurs:\n\n1. The Google app attempts to open your app's universal link. It's able to\n open your app if it's installed on the user's device and associated with\n the universal link. See [Supporting Universal Links](https://developer.apple.com/documentation/uikit/inter-process_communication/allowing_apps_and_websites_to_link_to_your_content) for details.\n\n2. Your app checks that the `client_id` and `redirect_uri` parameter encoded\n in the incoming URL matches the expected Google universal link.\n\n3. Your app requests an authorization code from your OAuth2 server. At the end\n of this flow, your app returns either an authorization code or an error to\n the Google app. To do this, it opens Google's universal link with appended\n parameters for the authorization code or error.\n\n4. The Google app handles the incoming Google universal link and continues with\n the rest of the flow. If an authorization code is provided, the linking is\n completed immediately. The token exchange happens server-to-server, the same\n way it does in the browser-based OAuth linking flow. If an error code is\n returned, the linking flow continues with the alternative options.\n\nModify your iOS app to support App Flip\n\nTo support App Flip, make the following code changes to your iOS app:\n\n1. Handle `NSUserActivityTypeBrowsingWeb` in your App Delegate.\n2. Capture `redirect_uri` and `state` parameters from the URL to use later.\n3. Check that `redirect_uri` matches this format: \n\n ```\n https://oauth-redirect.googleusercontent.com/a/GOOGLE_APP_BUNDLE_ID\n https://oauth-redirect-sandbox.googleusercontent.com/a/GOOGLE_APP_BUNDLE_ID\n ```\n4. Verify that the client ID matches the expected value. Use the following\n code sample:\n\n func application(_ application: UIApplication,\n continue userActivity: NSUserActivity,\n restorationHandler: @escaping ([Any]?) -\u003e Void) -\u003e Bool\n {\n guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,\n let incomingURL = userActivity.webpageURL,\n let components = URLComponents(url: incomingURL, resolvingAgainstBaseURL: false),\n let params = components.queryItems else {\n return false\n }\n\n if let clientId = params.filter({$0.name == \"client_id\"}).first?.value,\n let state = params.filter({$0.name == \"state\"}).first?.value,\n let redirectUri = params.filter({$0.name == \"redirect_uri\"}).first?.value {\n\n // Save the redirect_uri and state for later...\n\n // Verify the client id\n return (clientId == GOOGLE_CLIENT_ID)\n } else {\n // Missing required parameters\n return false\n }\n }\n\n5. Upon successful authorization, call the redirect URI with the authorization\n code. Use the following code sample:\n\n func returnAuthCode(code: String, state: String, redirectUri: String) {\n var redirectURL = URL(string: redirectUri)\n var components = URLComponents(url: redirectURL, resolvingAgainstBaseURL: false)\n\n // Return the authorization code and original state\n let paramAuthCode = URLQueryItem(name: \"code\", value: code)\n let paramState = URLQueryItem(name: \"state\", value: state)\n components?.queryItems = [paramAuthCode, paramState]\n if let resultURL = components?.url {\n UIApplication.shared.open(\n resultURL,\n options: [UIApplicationOpenURLOptionUniversalLinksOnly : true],\n completionHandler: nil)\n }\n }\n\n6. If an error occurred, attach an error result to the redirect URI instead.\n Use the following code sample:\n\n **Note:** Do not handle the error directly within your app, instead return the error result to the `REDIRECT_URL`. This ensures that the appropriate fallback method is trigerred if the app linking flow fails. \n\n func returnError(redirectUri: String) {\n var redirectURL = URL(string: redirectUri)\n var components = URLComponents(url: redirectURL, resolvingAgainstBaseURL: false)\n\n // Return the authorization code and original state\n let paramError = URLQueryItem(name: \"error\", value: \"invalid_request\")\n let paramDescription = URLQueryItem(name: \"error_description\", value: \"Invalid Request\")\n components?.queryItems = [paramError, paramDescription]\n if let resultURL = components?.url {\n UIApplication.shared.open(\n resultURL,\n options: [UIApplicationOpenURLOptionUniversalLinksOnly : true],\n completionHandler: nil)\n }\n }\n\nQuery parameters for your app's universal link\n\nWhen opened by the Google app, your app's universal link includes the following\nquery parameters:\n\n- `client_id` (`String`): Google `client_id` that's registered under your app.\n- `scope` (`List of String`): A list of space-separated scopes requested.\n- `state` (`String`): A nonce used by Google to verify that the authorization result is in response to Google's outgoing request.\n- `redirect_uri` (`String`): Google's universal link. The \"flip\" URI to open the Google app and pass results.\n\nQuery parameters for Google's universal link\n\nParameters used when the authorization result is returned successfully:\n\n- `code` (`String`): The value of the authorization code, if available.\n- `state` (`String`): The exact value received from the incoming universal link.\n\nParameters used when the authorization result is returned unsuccessfully:\n\n- `error` (`String`), with the following values:\n\n - `cancelled`: A recoverable error. The Google app will attempt account linking using the authorization URL. Some examples are the user failing to sign in, a device being offline or a connection timing out.\n - `unrecoverable`: An unrecoverable error. For example, the user attempts to link with a disabled account.The Google app will abort account linking.\n - `invalid_request`: The request parameters are invalid or missing. This is a recoverable error. The Google app will attempt account linking using the authorization URL.\n - `access_denied`: The user rejects the consent request. This is a non-recoverable error; the Google app aborts linking.\n- `error_description` (`String`, optional): A user-friendly error message.\n\n | **Note:** For more information on [possible errors](https://www.oauth.com/oauth2-servers/server-side-apps/possible-errors/) and the optional contents of the `error_description` field, see the OAuth 2.0 standard.\n\nFor all error types, you must return the response data to the specified\n`REDIRECT_URI` to ensure the appropriate fallback is trigerred.\n\nModify your authorization endpoint to support App Flip\n\nConfigure your platform to accept requests using Google's App Flip redirect URLs:\n\n- Google Home app \n\n ```\n https://oauth-redirect.googleusercontent.com/a/com.google.Chromecast.dev\n https://oauth-redirect.googleusercontent.com/a/com.google.Chromecast.enterprise\n https://oauth-redirect.googleusercontent.com/a/com.google.Chromecast\n https://oauth-redirect-sandbox.googleusercontent.com/a/com.google.Chromecast.dev\n https://oauth-redirect-sandbox.googleusercontent.com/a/com.google.Chromecast.enterprise\n https://oauth-redirect-sandbox.googleusercontent.com/a/com.google.Chromecast\n ```\n- Google Assistant app \n\n ```\n https://oauth-redirect.googleusercontent.com/a/com.google.OPA.dev\n https://oauth-redirect.googleusercontent.com/a/com.google.OPA.enterprise\n https://oauth-redirect.googleusercontent.com/a/com.google.OPA\n https://oauth-redirect-sandbox.googleusercontent.com/a/com.google.OPA.dev\n https://oauth-redirect-sandbox.googleusercontent.com/a/com.google.OPA.enterprise\n https://oauth-redirect-sandbox.googleusercontent.com/a/com.google.OPA\n ```\n\nCheck that `client_id` and the URL specified by the `redirect_uri` parameter\nmatch the expected values when a request is received. if the client verification\nfails, return the error `invalid_request` to the `redirect_uri`."]]