إضافة عناصر الجذب للمستخدمين إلى إضافة
تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
يمكنك منح المستخدمين الذين يثبّتون إضافتك إمكانية إدراج منطق مخصّص خاص بهم في عملية تنفيذ إضافتك. هناك طريقتان لتحقيق ذلك:
أحداث Eventarc: لمنح المستخدمين طريقة للتفاعل بشكل غير متزامن مع الأحداث، يمكنك النشر على Eventarc. يمكن للمستخدمين نشر وظائف معالجة الأحداث التي ترسل إشعارات مثلاً بعد اكتمال المهام الطويلة الأمد، أو يمكنهم تحديد وظائف المعالجة اللاحقة الخاصة بهم.
خطافات متزامنة: لمنح المستخدمين طريقة لإضافة منطق حظر إلى إضافتك، يمكنك إضافة خطافات متزامنة في نقاط محدّدة مسبقًا في عملية الإضافة. في هذه النقاط، يمكنك تشغيل دالة موفّر المستخدم
والمتابعة فقط بعد اكتمالها. وغالبًا ما تندرج مهام المعالجة المسبقة ضمن هذه الفئة.
يمكن أن تستخدم الإضافة إحدى الطريقتَين أو كلتيهما.
أحداث Eventarc
لنشر أحداث من إضافة، اتّبِع الخطوات التالية:
عليك تعريف أنواع الأحداث التي ستنشرها في ملف extension.yaml
:
events:
- type: publisher-id.extension-name.version.event-name
description: event-description
- type: publisher-id.extension-name.version.another-event-name
description: another-event-description
يتألف معرّف type
من عدة حقول مفصولة بنقاط. يجب ملء حقول
رقم تعريف الناشر واسم الإضافة واسم الحدث. ننصحك بملء حقل الإصدار. اختَر اسمًا فريدًا ووصفيًا للحدث لكل نوع حدث تنشره.
على سبيل المثال، يعرّف الامتداد storage-resize-images
نوع حدث واحدًا:
events:
- type: firebase.extensions.storage-resize-images.v1.complete
description: |
Occurs when image resizing completes. The event will contain further
details about specific formats and sizes.
سيتمكّن المستخدمون من اختيار الأحداث التي يريدون الاشتراك فيها عند تثبيت الإضافة.
في وظائف الإضافة، استورِد Eventarc API من Admin SDK
وأنشئ قناة أحداث باستخدام إعدادات التثبيت الخاصة بالمستخدم.
يتم عرض هذه الإعدادات باستخدام متغيرات البيئة التالية:
- استبدِل
EVENTARC_CHANNEL
بالاسم المؤهَّل بالكامل لقناة Eventarc التي اختار المستخدم نشر الأحداث فيها.
-
EXT_SELECTED_EVENTS
: قائمة مفصولة بفواصل لأنواع الأحداث التي اختار المستخدم نشرها. عند تهيئة قناة بهذه القيمة، ستعمل حزمة تطوير البرامج (SDK) للمشرف تلقائيًا على فلترة الأحداث التي لم يحدّدها المستخدم.
-
EVENTARC_CLOUD_EVENT_SOURCE
: معرّف مصدر Cloud Event. تنقل حزمة تطوير البرامج (SDK) الخاصة بخدمة Admin هذه القيمة تلقائيًا في الحقل source
للأحداث المنشورة. لا تحتاج عادةً إلى استخدام هذا المتغيّر بشكل صريح.
إذا لم يتم تفعيل الأحداث أثناء التثبيت، ستكون هذه المتغيرات غير محدّدة. يمكنك استخدام هذه الحقيقة لتهيئة قناة أحداث فقط عندما تكون الأحداث مفعّلة:
import * as admin from "firebase-admin";
import {getEventarc} from 'firebase-admin/eventarc';
admin.initializeApp();
// Set eventChannel to a newly-initialized channel, or `undefined` if events
// aren't enabled.
const eventChannel =
process.env.EVENTARC_CHANNEL &&
getEventarc().channel(process.env.EVENTARC_CHANNEL, {
allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
});
انشر الأحداث على القناة في النقاط التي تريد عرضها للمستخدمين في الإضافة. على سبيل المثال:
// If events are enabled, publish a `complete` event to the configured
// channel.
eventChannel && eventChannel.publish({
type: 'firebase.extensions.storage-resize-images.v1.complete',
subject: filename, // the name of the original file
data: {
// ...
}
});
وثِّق الأحداث التي تنشرها في ملف PREINSTALL أو POSTINSTALL.
بالنسبة إلى كل حدث، سجِّل ما يلي:
- الغرض المقصود منه
- النقطة التي يتم فيها تنفيذ منطق الإضافة
- بيانات الإخراج التي تتضمّنها
- شروط تنفيذها
بالإضافة إلى ذلك، يجب تحذير المستخدمين من عدم تنفيذ أي إجراءات في معالجات الأحداث التي قد تؤدي إلى تشغيل الإضافة نفسها، ما يؤدي إلى حدوث حلقة لا نهائية.
عند نشر أحداث من إضافة، يمكن للمستخدمين نشر معالجات أحداث
للاستجابة بمنطق مخصّص.
على سبيل المثال، يحذف المثال التالي الصورة الأصلية بعد تغيير حجمها. يُرجى العِلم أنّ معالج المثال هذا يستخدم السمة subject
الخاصة بالحدث، وهي في هذه الحالة اسم الملف الأصلي للصورة.
exports.onimageresized = onCustomEventPublished(
"firebase.extensions.storage-resize-images.v1.complete",
(event) => {
logger.info("Received image resize completed event", event);
// For example, delete the original.
return admin.storage()
.bucket("my-project.firebasestorage.app")
.file(event.subject)
.delete();
});
اطّلِع على عوامل تشغيل الأحداث المخصّصة لمزيد من المعلومات.
مثال
توفّر إضافة Resize Images الرسمية
خطافًا غير متزامن من خلال النشر إلى Eventarc
بعد تغيير حجم الصورة.
عبارات الربط المتزامنة
عندما تريد تزويد المستخدمين بخطاف يجب أن يكتمل بنجاح
لكي تعمل إحدى وظائف الإضافة، استخدِم خطافات متزامنة.
يستدعي الخطاف المتزامن دالة Cloud قابلة للاستدعاء عبر HTTPS يحدّدها المستخدم وينتظر اكتمالها (ربما مع قيمة معروضة) قبل المتابعة. يؤدي حدوث خطأ في الدالة التي يقدّمها المستخدم إلى حدوث خطأ في دالة الإضافة.
لعرض خطاف متزامن، اتّبِع الخطوات التالية:
أضِف مَعلمة إلى الإضافة تسمح للمستخدمين بضبط الإضافة باستخدام عنوان URL الخاص بـ Cloud Function المخصّصة. على سبيل المثال:
- param: PREPROCESSING_FUNCTION
label: Pre-processing function URL
description: >
An HTTPS callable function that will be called to transform the input data
before it is processed by this function.
type: string
example: https://us-west1-my-project-id.cloudfunctions.net/preprocessData
required: false
في النقطة التي تريد فيها عرض الخطاف في الإضافة، استدعِ الدالة باستخدام عنوان URL الخاص بها. على سبيل المثال:
const functions = require('firebase-functions/v1');
const fetch = require('node-fetch');
const preprocessFunctionURL = process.env.PREPROCESSING_FUNCTION;
exports.yourFunctionName = functions.firestore.document("collection/{doc_id}")
.onWrite((change, context) => {
// PREPROCESSING_FUNCTION hook begins here.
// If a preprocessing function is defined, call it before continuing.
if (preprocessFunctionURL) {
try {
await fetch(preprocessFunctionURL); // Could also be a POST request if you want to send data.
} catch (e) {
// Preprocessing failure causes the function to fail.
functions.logger.error("Preprocessor error:", e);
return;
}
}
// End of PREPROCESSING_FUNCTION hook.
// Main function logic follows.
// ...
});
وثِّق أي خطافات توفّرها في ملف PREINSTALL أو POSTINSTALL.
لكل خطاف، يجب توثيق ما يلي:
- الغرض المقصود منه
- النقطة التي يتم فيها تنفيذ منطق الإضافة
- المدخلات والمخرجات المتوقّعة
- شروط (أو خيارات) تنفيذها
بالإضافة إلى ذلك، يجب تحذير المستخدمين من عدم تنفيذ أي إجراءات في دالة الخطاف قد تؤدي إلى تشغيل الإضافة نفسها، ما يؤدي إلى حدوث حلقة لا نهائية.
مثال
توفّر إضافة Algolia Search
خطافًا متزامنًا لاستدعاء دالة تحويل يوفّرها المستخدم
قبل الكتابة إلى Algolia.
إنّ محتوى هذه الصفحة مرخّص بموجب ترخيص Creative Commons Attribution 4.0 ما لم يُنصّ على خلاف ذلك، ونماذج الرموز مرخّصة بموجب ترخيص Apache 2.0. للاطّلاع على التفاصيل، يُرجى مراجعة سياسات موقع Google Developers. إنّ Java هي علامة تجارية مسجَّلة لشركة Oracle و/أو شركائها التابعين.
تاريخ التعديل الأخير: 2025-07-25 (حسب التوقيت العالمي المتفَّق عليه)
[null,null,["تاريخ التعديل الأخير: 2025-07-25 (حسب التوقيت العالمي المتفَّق عليه)"],[],[],null,["\u003cbr /\u003e\n\nYou can provide users who install your extension the ability to insert their own\ncustom logic into the execution of your extension. There are two ways to\naccomplish this:\n\n- **Eventarc events**: to give users a way to asynchronously react to\n events, you can publish to Eventarc. Users can deploy event handler\n functions that, for example, send notifications after long-running\n tasks complete, or they can define their own post-processing functions.\n\n- **Synchronous hooks**: to give users a way to add blocking logic to your\n extension, you can add synchronous hooks at predefined points in the\n extension's operation. At these points, you run a user-provider function\n and proceed only after it completes. Pre-processing tasks often fall under\n this category.\n\nAn extension can use either or both methods.\n\nEventarc events\n\nTo publish events from an extension:\n\n1. Declare the event types you will publish in the `extension.yaml` file:\n\n events:\n - type: publisher-id.extension-name.version.event-name\n description: event-description\n - type: publisher-id.extension-name.version.another-event-name\n description: another-event-description\n\n The `type` identifier is made of several dot-delimited fields. The\n [publisher ID](/docs/extensions/publishers/register), extension name, and event name fields are\n required. The version field is recommended. Choose a unique and descriptive\n event name for each event type you publish.\n\n For example, the [`storage-resize-images` extension](https://github.com/firebase/extensions/blob/next/storage-resize-images/extension.yaml)\n declares a single event type: \n\n events:\n - type: firebase.extensions.storage-resize-images.v1.complete\n description: |\n Occurs when image resizing completes. The event will contain further\n details about specific formats and sizes.\n\n Users will be able to choose which events to subscribe to when they\n install the extension.\n2. In your extension functions, import the Eventarc API from the Admin SDK\n and initialize an event channel using the user's installation settings.\n These settings are exposed using the following environment variables:\n\n - `EVENTARC_CHANNEL`: the fully-qualified name of the Eventarc channel to which the user chose to publish events.\n - `EXT_SELECTED_EVENTS`: a comma-separated list of event types the user chose to publish. When you initialize a channel with this value, the Admin SDK automatically filters out events user did not select.\n - `EVENTARC_CLOUD_EVENT_SOURCE`: the Cloud Event source identifier. The Admin SDK automatically passes this value in the `source` field of published events. You typically don't need to explicitly use this variable.\n\n If events weren't enabled at installation, these variables will be\n undefined. You can use this fact to initialize an event channel only when\n events are enabled: \n\n import * as admin from \"firebase-admin\";\n import {getEventarc} from 'firebase-admin/eventarc';\n\n admin.initializeApp();\n\n // Set eventChannel to a newly-initialized channel, or `undefined` if events\n // aren't enabled.\n const eventChannel =\n process.env.EVENTARC_CHANNEL &&\n getEventarc().channel(process.env.EVENTARC_CHANNEL, {\n allowedEventTypes: process.env.EXT_SELECTED_EVENTS,\n });\n\n3. Publish events to the channel at the points in your extension you want to\n expose to users. For example:\n\n // If events are enabled, publish a `complete` event to the configured\n // channel.\n eventChannel && eventChannel.publish({\n type: 'firebase.extensions.storage-resize-images.v1.complete',\n subject: filename, // the name of the original file\n data: {\n // ...\n }\n });\n\n4. Document the events you publish, in either the PREINSTALL or POSTINSTALL\n file.\n\n For each event, document the following:\n - Its intended purpose\n - The point in your extension's logic it runs\n - The output data it includes\n - The conditions for its execution\n\n Additionally, warn users not to perform any actions in their event\n handlers that might trigger the same extension, resulting in an infinite\n loop.\n\nWhen you publish events from an extension, users can deploy event handlers\nto respond with custom logic.\n\nFor example, the following example deletes the original image after it has been\nresized. Note that this example handler makes use of the `subject` property of\nthe event, which in this case is the image's original filename. \n\n exports.onimageresized = onCustomEventPublished(\n \"firebase.extensions.storage-resize-images.v1.complete\",\n (event) =\u003e {\n logger.info(\"Received image resize completed event\", event);\n // For example, delete the original.\n return admin.storage()\n .bucket(\"my-project.firebasestorage.app\")\n .file(event.subject)\n .delete();\n });\n\nSee [Custom event triggers](/docs/functions/custom-events#handle-events) for more\ninformation.\n\nExample\n\nThe official [Resize Images extension](https://github.com/firebase/extensions/tree/next/storage-resize-images)\nprovides an asynchronous hook by [publishing to Eventarc](https://github.com/firebase/extensions/blob/c29781c7e67c004e2491e4ce3c43b25b05bd3de6/storage-resize-images/functions/src/index.ts#L109-L117)\nafter resizing an image.\n\nSynchronous hooks\n\nWhen you want to provide users with a hook that must complete successfully\nfor one of your extension functions to operate, use *synchronous hooks*.\n\nA synchronous hook calls a user-defined [HTTPS callable Cloud\nFunction](/docs/functions/http-events) and awaits completion (possibly with a\nreturned value) before continuing. An error in the user-provided function\nresults in an error in the extension function.\n\nTo expose a synchronous hook:\n\n1. Add a parameter to your extension that allows users to configure the\n extension with the URL to their custom Cloud Function. For example:\n\n - param: PREPROCESSING_FUNCTION\n label: Pre-processing function URL\n description: \u003e\n An HTTPS callable function that will be called to transform the input data\n before it is processed by this function.\n type: string\n example: https://us-west1-my-project-id.cloudfunctions.net/preprocessData\n required: false\n\n2. At the point in your extension where you want to expose the hook, call the\n function using its URL. For example:\n\n const functions = require('firebase-functions/v1');\n const fetch = require('node-fetch');\n\n const preprocessFunctionURL = process.env.PREPROCESSING_FUNCTION;\n\n exports.yourFunctionName = functions.firestore.document(\"collection/{doc_id}\")\n .onWrite((change, context) =\u003e {\n // PREPROCESSING_FUNCTION hook begins here.\n // If a preprocessing function is defined, call it before continuing.\n if (preprocessFunctionURL) {\n try {\n await fetch(preprocessFunctionURL); // Could also be a POST request if you want to send data.\n } catch (e) {\n // Preprocessing failure causes the function to fail.\n functions.logger.error(\"Preprocessor error:\", e);\n return;\n }\n }\n // End of PREPROCESSING_FUNCTION hook.\n\n // Main function logic follows.\n // ...\n });\n\n3. Document any hooks you make available in either the PREINSTALL or\n POSTINSTALL file.\n\n For each hook, document the following:\n - Its intended purpose\n - The point in your extension's logic it runs\n - Its expected inputs and outputs\n - The conditions (or options) for its execution\n\n Additionally, warn users not to perform any actions in the hook\n function that might trigger the same extension, resulting in an infinite\n loop.\n\nExample\n\nThe [Algolia Search extension](https://github.com/algolia/firestore-algolia-search/)\nprovides a synchronous hook to [call a user-supplied transform function](https://github.com/algolia/firestore-algolia-search/blob/34592d513eac22691d76917874a6466032976f67/functions/src/transform.ts)\nprior to writing to Algolia."]]