تتمثل إحدى الطرق الأكثر فاعلية لجذب مستخدمين جدد لتثبيت تطبيقك في تمكين المستخدمين من مشاركة المحتوى من تطبيقك مع أصدقائهم. باستخدام الروابط الديناميكية ، يمكنك إنشاء تجربة مشاركة رائعة من مستخدم إلى مستخدم: يمكن للمستخدمين الذين يتلقون توصيات المحتوى من أصدقائهم النقر فوق ارتباط ونقلهم مباشرةً إلى المحتوى المشترك في تطبيقك ، حتى إذا كان عليهم الانتقال إلى التطبيق متجر أو متجر Google Play لتثبيت التطبيق الخاص بك أولاً.
من خلال الجمع بين ثبات إحالات المستخدمين واستمرار الروابط الديناميكية ، يمكنك إنشاء ميزات مشاركة وإحالة من مستخدم إلى مستخدم تجلب مستخدمين جددًا عن طريق جذبهم مباشرةً إلى محتوى تطبيقك أو تقديم العروض الترويجية التي تفيد المُحيل والمشار إليه بشكل متبادل .
الفوائد الرئيسية
- يحصل المستخدمون الجدد الذين يفتحون تطبيقك لأول مرة على تجربة تشغيل مخصصة لأول مرة يتم وضعها في سياقها بناءً على ما يريد أصدقاؤهم مشاركته معهم. على سبيل المثال ، يمكنك عرض المحتوى الذي تمت مشاركته معهم ، أو ربطهم تلقائيًا بالصديق الذي دعاهم.
- يُسهل على المستخدمين مشاركة المحتوى مع أصدقائهم عبر الأنظمة الأساسية سواء قام أصدقاؤهم بتثبيت تطبيقك أم لا.
إليك كيفية البدء!
إعداد Firebase و Dynamic Links SDK
قم بإعداد مشروع Firebase جديد وتثبيت Dynamic Links SDK في تطبيقك.
يسمح تثبيت Dynamic Links SDK لـ Firebase بتمرير البيانات حول الرابط الديناميكي إلى التطبيق ، بما في ذلك بعد تثبيت المستخدم للتطبيق.
إنشاء روابط ديناميكية
حان الوقت الآن لإعداد الروابط التي يمكن للمستخدمين إرسالها إلى أصدقائهم. لا تقلق إذا لم يكن التطبيق مثبتًا لدى أصدقاء المستخدمين لديك ؛ يمكن أن تعتني الروابط الديناميكية بذلك نيابة عنك.
لكل عنصر من عناصر المحتوى تريد أن تكون قابلاً للمشاركة ، قم بإنشاء ارتباط ديناميكي .
عند إنشاء الارتباط الديناميكي ، ستحتاج إلى توفير عنوان URL لـ HTTP أو HTTPS كمعلمة link
التي سيتم استخدامها لتحديد المحتوى الذي تشاركه. إذا كان لديك موقع ويب به محتوى مكافئ ، فيجب عليك استخدام عناوين URL لموقع الويب الخاص بك. سيضمن ذلك عرض هذه الروابط بشكل صحيح على نظام أساسي لا يدعم الروابط الديناميكية ، مثل متصفح سطح المكتب. على سبيل المثال:
https://example.page.link/?link=https://www.example.com/content?item%3D1234&apn=com.example.android&ibi=com.example.ios&isi=12345
يمكنك أيضًا إضافة معلومات إضافية إلى حمولة البيانات عن طريق إضافة معلمات مشفرة بعنوان URL - على سبيل المثال ، للإشارة إلى أن الرابط مخصص لمستخدم معين ، كما هو الحال في دعوة لعبة.
https://example.page.link/?link=https://www.example.com/invitation?gameid%3D1234%26referrer%3D555&apn=com.example.android&ibi=com.example.ios&isi=12345
قبل مشاركة هذه الروابط ، قد ترغب في استخدام Firebase Dynamic Links URL shortener API لإنشاء عناوين URL أكثر ودية. يشبه الارتباط الديناميكي القصير المثال التالي:
https://example.page.link/WXYZ
أيًا كان الرابط الذي تستخدمه ، عندما يفتح المستخدمون الرابط الديناميكي على أجهزتهم ، فإن التطبيق المحدد بواسطة معلمة apn
(على Android) أو معلمات ibi
و isi
(على iOS) سينقل المستخدمين إلى متجر Play أو متجر التطبيقات لتثبيت التطبيق إذا لم يكن مثبتًا بالفعل. بعد ذلك ، عند تثبيت التطبيق وفتحه ، يتم تمرير عنوان URL المحدد في معلمة "الرابط" إلى التطبيق.
أضف أزرار "مشاركة" التي ترسل روابط ديناميكية
أولاً ، ألق نظرة على هذا المثال البسيط لتطبيق الدردشة القائم على الغرفة مثل Hangouts الذي ينشئ روابط لدعوة الأشخاص إلى غرف الدردشة.
iOS


ذكري المظهر


سويفت
func generateContentLink() -> URL { let baseURL = URL(string: "https://your-custom-name.page.link")! let domain = "https://your-app.page.link" let linkBuilder = DynamicLinkComponents(link: baseURL, domainURIPrefix: domain) linkBuilder?.iOSParameters = DynamicLinkIOSParameters(bundleID: "com.your.bundleID") linkBuilder?.androidParameters = DynamicLinkAndroidParameters(packageName: "com.your.packageName") // Fall back to the base url if we can't generate a dynamic link. return linkBuilder?.link ?? baseURL }
ج موضوعية
- (NSURL *)generateContentLink { NSURL *baseURL = [NSURL URLWithString:@"https://your-custom-name.page.link"]; NSString *domain = @"https://your-app.page.link"; FIRDynamicLinkComponents *builder = [[FIRDynamicLinkComponents alloc] initWithLink:baseURL domainURIPrefix:domain]; builder.iOSParameters = [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.your.bundleID"]; builder.androidParameters = [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.your.packageName"]; // Fall back to the base url if we can't generate a dynamic link. return builder.link ?: baseURL; }
Kotlin+KTX
fun generateContentLink(): Uri { val baseUrl = Uri.parse("https://your-custom-name.page.link") val domain = "https://your-app.page.link" val link = FirebaseDynamicLinks.getInstance() .createDynamicLink() .setLink(baseUrl) .setDomainUriPrefix(domain) .setIosParameters(DynamicLink.IosParameters.Builder("com.your.bundleid").build()) .setAndroidParameters(DynamicLink.AndroidParameters.Builder("com.your.packageName").build()) .buildDynamicLink() return link.uri }
Java
public static Uri generateContentLink() { Uri baseUrl = Uri.parse("https://your-custom-name.page.link"); String domain = "https://your-app.page.link"; DynamicLink link = FirebaseDynamicLinks.getInstance() .createDynamicLink() .setLink(baseUrl) .setDomainUriPrefix(domain) .setIosParameters(new DynamicLink.IosParameters.Builder("com.your.bundleid").build()) .setAndroidParameters(new DynamicLink.AndroidParameters.Builder("com.your.packageName").build()) .buildDynamicLink(); return link.getUri(); }
بمجرد أن يكون لديك رابط ديناميكي ، يمكنك إضافة زر مشاركة إلى واجهة المستخدم الخاصة بك والتي ستطلق تدفق مشاركة النظام الأساسي القياسي:
سويفت
lazy private var shareController: UIActivityViewController = { let activities: [Any] = [ "Learn how to share content via Firebase", URL(string: "https://firebase.google.com")! ] let controller = UIActivityViewController(activityItems: activities, applicationActivities: nil) return controller }() @IBAction func shareButtonPressed(_ sender: Any) { let inviteController = UIStoryboard(name: "Main", bundle: nil) .instantiateViewController(withIdentifier: "InviteViewController") self.navigationController?.pushViewController(inviteController, animated: true) }
ج موضوعية
- (UIActivityViewController *)shareController { if (_shareController == nil) { NSArray *activities = @[ @"Learn how to share content via Firebase", [NSURL URLWithString:@"https://firebase.google.com"] ]; UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:activities applicationActivities:nil]; _shareController = controller; } return _shareController; } - (IBAction)shareLinkButtonPressed:(UIView *)sender { if (![sender isKindOfClass:[UIView class]]) { return; } self.shareController.popoverPresentationController.sourceView = sender; [self presentViewController:self.shareController animated:YES completion:nil]; }
Kotlin+KTX
private fun onShareClicked() { val link = DynamicLinksUtil.generateContentLink() val intent = Intent(Intent.ACTION_SEND) intent.type = "text/plain" intent.putExtra(Intent.EXTRA_TEXT, link.toString()) startActivity(Intent.createChooser(intent, "Share Link")) }
Java
private void onShareClicked() { Uri link = DynamicLinksUtil.generateContentLink(); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, link.toString()); startActivity(Intent.createChooser(intent, "Share Link")); }
في هذا المثال ، تعرض واجهة المستخدم الافتراضية للمشاركة تلقائيًا قائمة بالتطبيقات لمشاركة الرابط ، لذا فهو شيء يمكنك إعداده في التطبيق الخاص بك ببضعة سطور من التعليمات البرمجية.
بدلاً من جعل المستخدم يختار جهات الاتصال ويؤلف الرسالة في تطبيقك ، يتم تفويض هذه الإجراءات إلى التطبيق الذي يختاره من مربع حوار المشاركة. بالإضافة إلى ذلك ، يعني تفويض المشاركة إلى تطبيقات أخرى أنك لست مضطرًا إلى مطالبة المستخدم بأذونات جهات الاتصال والسماح للمستخدمين بالاختيار من قائمة جهات اتصال موسعة داخل التطبيق الذي يختارونه. لتسهيل المشاركة الاجتماعية بشكل أفضل ، يمكنك إضافة بيانات وصفية لمعاينة الوسائط الاجتماعية إلى الرابط الديناميكي الذي سيتم عرضه مع الرابط في القنوات الاجتماعية الرئيسية.
في بعض الأحيان ، على الرغم من ذلك ، فإن مجرد إرسال رابط خالٍ بدون نص لا يكفي لإحالة مقنعة. من خلال إرفاق الرابط برسالة قصيرة ، وإذا أمكن ، عرض تقديمي أكثر ثراءً ، يمكن للمستخدمين فهم عرض قيمة الإحالة عند تلقيه:
iOS


ذكري المظهر


على الرغم من أن هذا أكثر تعقيدًا من المثال الأخير ، إلا أن الطريقة ستكون متشابهة إلى حد ما. يوجد على هذه الشاشة رسم كبير مع عرض قيمة الدعوة وأزرار للمشاركة في القنوات الاجتماعية الرئيسية. هناك بعض التكرار في تدفق واجهة المستخدم هذا - يتم تقديم بعض قنوات المشاركة بشكل فردي للسماح بمزيد من تخصيص الرسائل الخاصة بالقناة ، مثل إضافة سطر موضوع إلى دعوات البريد الإلكتروني. في قائمة الدعوة هذه ، نقوم بما يلي:
- يمكنك تقديم البريد الإلكتروني والرسالة النصية وأزرار مشاركة الارتباط بنسخها وتخصيص رسائلها بشكل مناسب. سيتضمن البريد الإلكتروني موضوعًا ويمكن أن يتضمن نصًا أطول به فواصل أسطر وصور ومسافات بيضاء ؛ يجب أن يشتمل النص على نص أقصر به فواصل أسطر ولكن القليل من المسافات البيضاء وبدون صور ؛ ونسخ الرابط يجب أن ينسخ الرابط فقط ولا شيء آخر.
- استخدم واجهة مستخدم مشاركة النظام لكل شيء آخر ، بما في ذلك رسالة دعوة قصيرة لمرافقة الرابط.
- رابط عميق عبر مخطط عنوان URL أو رابط عام لتطبيق آخر له منطق خاص للتعامل مع دعوات تطبيقك. لن يعمل هذا خارج الشراكة بين مؤسستك والتطبيق الآخر ، ومن المحتمل ألا يكون خيارًا للمؤسسات الصغيرة. ومع ذلك ، قد توثق بعض التطبيقات علنًا سلوكها العام / الرابط العميق. سنقوم بتنفيذ نسخة وهمية من هذا في عينتنا.
أولاً ، حدد نوع محتوى الدعوة ، والذي يتضمن فقط المعلومات الواردة في الدعوة ولا يحتوي على أي وظيفة. بهذه الطريقة ، يمكنك البدء بأنواع البيانات والتفكير في الكود الخاص بك من حيث كيفية تجميع هذه البيانات معًا.
سويفت
/// The content within an invite, with optional fields to accommodate all presenters. /// This type could be modified to also include an image, for sending invites over email. struct InviteContent { /// The subject of the message. Not used for invites without subjects, like text message invites. var subject: String? /// The body of the message. Indispensable content should go here. var body: String? /// The URL containing the invite. In link-copy cases, only this field will be used. var link: URL }
ج موضوعية
/// The content within an invite, with optional fields to accommodate all presenters. /// This type could be modified to also include an image, for sending invites over email. @interface InviteContent : NSObject <NSCopying> /// The subject of the message. Not used for invites without subjects, like text message invites. @property (nonatomic, readonly, nullable) NSString *subject; /// The body of the message. Indispensable content should go here. @property (nonatomic, readonly, nullable) NSString *body; /// The URL containing the invite. In link-copy cases, only this field will be used. @property (nonatomic, readonly) NSURL *link; - (instancetype)initWithSubject:(nullable NSString *)subject body:(nullable NSString *)body link:(NSURL *)link NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; @end
Kotlin+KTX
/** * The content of an invitation, with optional fields to accommodate all presenters. * This type could be modified to also include an image, for sending invites over email. */ data class InviteContent( /** The subject of the message. Not used for invites without subjects, like SMS. */ val subject: String?, /** The body of the message. Indispensable content should go here. */ val body: String?, /** The URL containing the link to invite. In link-copy cases, only this field will be used. */ val link: Uri )
Java
/** * The content of an invitation, with optional fields to accommodate all presenters. * This type could be modified to also include an image, for sending invites over email. */ public class InviteContent { /** * The subject of the message. Not used for invites without subjects, like SMS. **/ @Nullable public final String subject; /** * The body of the message. Indispensable content should go here. **/ @Nullable public final String body; /** * The URL containing the link to invite. In link-copy cases, only this field will be used. **/ @NonNull public final Uri link; public InviteContent(@Nullable String subject, @Nullable String body, @NonNull Uri link) { // ... } }
الجزء الوحيد المطلوب من البيانات هنا هو عنوان URL ، والذي بدونه لا يمكنك دعوة المستخدمين إلى تطبيقك. تم تصميم الأجزاء الأخرى من البيانات بشكل واضح نحو إرسال رسائل البريد الإلكتروني ، مما يجعلها محرجة قليلاً في بعض الحالات الأخرى - عند إرسال دعوة عبر النص ، قد يقرأ الدعاية المصاحبة للرابط بشكل مشابه لموضوع البريد الإلكتروني ، ولكن عند المشاركة على وسائل التواصل الاجتماعي قد يكون الارتباط المصاحب للنص أشبه بجسم بريد إلكتروني. سيتعين عليك تجربة هذا بنفسك للعثور على أفضل توازن لتطبيقك ، وإذا لم تكن متأكدًا ، فيمكنك دائمًا استخدام خدمة مثل Remote Config للسماح لك بتغيير قيم النص بعد تشغيل التطبيق.
سويفت
/// A type responsible for presenting an invite given using a specific method /// given the content of the invite. protocol InvitePresenter { /// The name of the presenter. User-visible. var name: String { get } /// An icon representing the invite method. User-visible. var icon: UIImage? { get } /// Whether or not the presenter's method is available. iOS devices that aren't phones /// may not be able to send texts, for example. var isAvailable: Bool { get } /// The content of the invite. Some of the content type's fields may be unused. var content: InviteContent { get } /// Designated initializer. init(content: InviteContent, presentingController: UIViewController) /// This method should cause the presenter to present the invite and then handle any actions /// required to complete the invite flow. func sendInvite() }
ج موضوعية
/// A type responsible for presenting an invite given using a specific method /// given the content of the invite. @protocol InvitePresenter <NSObject> /// The name of the presenter. User-visible. @property (nonatomic, readonly) NSString *name; /// An icon representing the invite method. User-visible. @property (nonatomic, readonly, nullable) UIImage *icon; /// Whether or not the presenter's method is available. iOS devices that aren't phones /// may not be able to send texts, for example. @property (nonatomic, readonly) BOOL isAvailable; /// The content of the invite. Some of the content type's fields may be unused. @property (nonatomic, readonly) InviteContent *content; /// Designated initializer. - (instancetype)initWithContent:(InviteContent *)content presentingViewController:(UIViewController *)controller; /// This method should cause the presenter to present the invite and then handle any actions /// required to complete the invite flow. - (void)sendInvite; @end
Kotlin+KTX
/** * Presents the invite using a specific method, such as email or social. */ open class InvitePresenter( /** The user-visible name of the invite method, like 'Email' or 'SMS' */ val name: String, /** An icon representing the invite method. */ @param:DrawableRes @field:DrawableRes val icon: Int, /** Whether or not the method is available on this device. For example, SMS is phone only. */ val isAvailable: Boolean, /** The Content of the invitation */ val content: InviteContent ) { /** * Send the invitation using the specified method. */ open fun sendInvite(context: Context) { // ... } }
Java
/** * Presents the invite using a specific method, such as email or social. */ public class InvitePresenter { /** * The user-visible name of the invite method, like 'Email' or 'SMS' **/ public final String name; /** * An icon representing the invite method. **/ @DrawableRes public final int icon; /** * Whether or not the method is available on this device. For example, SMS is phone only. **/ public final boolean isAvailable; /** * The Content of the invitation **/ public final InviteContent content; public InvitePresenter(String name, @DrawableRes int icon, boolean isAvailable, InviteContent content) { // ... } /** * Send the invitation using the specified method. */ public void sendInvite(Context context) { // ... } }
الآن كل ما تبقى هو توصيل هذا بمكون واجهة المستخدم الذي تختاره. للتنفيذ الكامل لتدفق الدعوة هذا ، راجع العينات على GitHub لنظامي التشغيل iOS و Android .
هذه كلها طرق لتمكين المستخدمين لديك من إرسال دعوات إلى أصدقائهم ، وهو حل الدعوة الأقل وزنًا. تقدم العديد من التطبيقات الشائعة أيضًا دعوات عن طريق إرسال رسائل البريد الإلكتروني من خلال الواجهة الخلفية الخاصة بها ، والتي تتطلب دمج خدمة إرسال البريد ، ولكنها تقدم عددًا من المزايا التي لا تتوفر بخلاف ذلك مع بعض العيوب البسيطة فقط.
الايجابيات:
- لتمكين رسائل البريد الإلكتروني ذات الترميز المعقد الذي لا يمكن للمستخدم تعديله قبل الإرسال.
- يتيح مزيدًا من التتبع / التحليلات الدقيقة (على سبيل المثال ، إرسال حالات النجاح والفشل على الواجهة الخلفية الخاصة بك).
سلبيات:
- من المرجح أن يتم وضع علامة على رسائل البريد الإلكتروني كرسائل غير مرغوب فيها
- يتطلب التكامل مع خدمة تسليم البريد الإلكتروني
- يتطلب أذونات جهات الاتصال داخل التطبيق
بشكل عام ، يوفر إرسال الدعوات من خلال خدمة توصيل البريد الإلكتروني الخاصة بك تجربة دعوة أكثر اتساقًا وربما أكثر ثراءً على حساب تعدد الاستخدامات.
افتح المحتوى المرتبط في تطبيقك
أخيرًا ، تحتاج إلى تلقي الرابط الذي تم تمريره إلى تطبيقك حتى تتمكن من عرض المحتوى المرتبط بالمستلم. هذا سهل باستخدام Dynamic Links SDK:
iOS
على نظام iOS ، تتلقى الرابط الديناميكي من خلال تنفيذ application:continueUserActivity:restorationHandler:
method. في معالج الاستعادة ، يمكنك الحصول على الرابط الديناميكي عن طريق استدعاء handleUniversalLink:completion:
إذا تم تمرير رابط ديناميكي إلى تطبيقك ، فيمكنك الحصول عليه من خاصية url
الخاصة بـ FIRDynamicLink
. علي سبيل المثال:
ج موضوعية
[[FIRDynamicLinks dynamicLinks]
handleUniversalLink:userActivity.webpageURL
completion:^(FIRDynamicLink * _Nullable dynamicLink,
NSError * _Nullable error) {
NSString *link = dynamicLink.url;
BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
// ...
}];
سويفت
FIRDynamicLinks.dynamicLinks()?.handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
let link = dynamicLink.url
let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
// ...
}
بالإضافة إلى ذلك ، يجب عليك استدعاء dynamicLinkFromCustomSchemeURL:
في application:openURL:options:
طريقة لتلقي الروابط الديناميكية التي تم تمريرها إلى تطبيقك كعناوين URL للمخطط المخصص. علي سبيل المثال:
ج موضوعية
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
NSString *link = dynamicLink.url;
BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
// ...
return YES;
}
سويفت
let dynamicLink = FIRDynamicLinks.dynamicLinks()?.dynamicLinkFromCustomSchemeURL(url)
if let dynamicLink = dynamicLink {
let link = dynamicLink.url
let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
// ...
return true
}
الآن بعد أن أصبحت لديك قيمة معلمة link
، يمكنك عرض المحتوى المرتبط للمستلم ، أو معالجة البيانات المحددة بواسطة المعلمة بطريقة أخرى. يمكن لمكتبة توجيه URL مثل JLRoutes المساعدة في هذه المهمة.
إذا كنت تتلقى رابطًا مخصصًا لمستلم معين ، فتأكد من أن ثقة مطابقة الرابط الديناميكي strong
قبل تشغيل أي منطق خاص بالمستخدم.
ذكري المظهر
في نظام Android ، يمكنك استخدام طريقة getDynamicLink()
للحصول على البيانات من الرابط الديناميكي:
Kotlin+KTX
Firebase.dynamicLinks .getDynamicLink(intent) .addOnCompleteListener { task -> if (!task.isSuccessful) { // Handle error // ... } val invite = FirebaseAppInvite.getInvitation(task.result) if (invite != null) { // Handle invite // ... } }
Java
FirebaseDynamicLinks.getInstance() .getDynamicLink(getIntent()) .addOnCompleteListener(new OnCompleteListener<PendingDynamicLinkData>() { @Override public void onComplete(@NonNull Task<PendingDynamicLinkData> task) { if (!task.isSuccessful()) { // Handle error // ... } FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(task.getResult()); if (invite != null) { // Handle invite // ... } } });
الآن بعد أن أصبحت لديك قيمة معلمة link
، يمكنك عرض المحتوى المرتبط للمستلم ، أو معالجة البيانات المحددة بواسطة المعلمة بطريقة أخرى. يمكن أن تساعد مكتبة توجيه عناوين URL في هذه المهمة.