حزم الجوال

حزم الجوال (SDK)

أطلِق محادثة أصيلة داخل تطبيقاتك على iOS وAndroid وFlutter وReact Native. تستضيف كل حزمة تجربة محادثة عون كير وتربط أحداثها بكودك الأصيل.

كيف تعمل

كل حزمة جوال هي غلاف أصيل رفيع حول صفحة المحادثة المستضافة نفسها — فتحصل على تجربة الودجت الكاملة، محدّثة من الخادم، ببصمة صغيرة.

تحمّل الحزمة صفحة المحادثة المستضافة (‏/widget/mobile) داخل WebView خاص بالمنصة. ويُمرَّر معرّف مساحة العمل واللغة ولون العلامة وبيانات الزائر كمعاملات في الرابط، فتنطلق الودجت مهيّأة وجاهزة.

تُمرَّر أحداث الودجت من الصفحة إلى كودك الأصيل عبر قناة رسائل، ويتحكّم الكود الأصيل في الودجت عبر واجهة JavaScript مُحقونة تُسمّى AwnCareMobile. هذا الجسر ثنائي الاتجاه هو ما يشغّل التعريف وشارات غير المقروء والتحكم في الفتح والإغلاق.

رابط المحادثة المستضاف

هذه هي الصفحة التي تحمّلها كل حزمة. لا تبنيها عادةً يدويًا — بل تجمّعها الحزمة لك من الإعدادات التي تمرّرها. ومعامل metadata عبارة عن JSON مُرمَّز بصيغة base64url.

text
https://awn.care/widget/mobile
  ?workspaceId=YOUR_WORKSPACE_ID
  &locale=ar
  &color=%232431E0
  &name=Sara
  &email=sara%40acme.sa
  &metadata=eyJwbGFuIjoicHJvIn0
تُوزَّع الحزم عبر git. ثبّت نسخة مُصدَرة (‏1.0.0) لتبقى بُنى مشروعك قابلة لإعادة الإنتاج.

iOS · سويفت

حزمة Swift لتطبيقات UIKit وSwiftUI، تُوزَّع عبر Swift Package Manager.

التثبيت

أضِف الحزمة في Xcode من رابط Git الخاص بها، أو صرّح بها في Package.swift، ثم استورد AwnCareSDK.

swift
// Swift Package Manager
// Xcode ▸ File ▸ Add Package Dependencies… then enter the package URL
// and pin to "Up to Next Major Version" from 1.0.0:
https://github.com/awncare/awncare-ios

// …or add it to Package.swift:
dependencies: [
  .package(url: "https://github.com/awncare/awncare-ios", from: "1.0.0"),
]

البدء السريع

هيّئ مرة واحدة بمعرّف مساحة العمل، ثم اعرض المحادثة بملء الشاشة من أي view controller.

swift
import AwnCareSDK

AwnCare.configure(workspaceId: "YOUR_WORKSPACE_ID", locale: "ar", color: "#2431E0")

// Present the chat full-screen from any UIViewController:
AwnCare.present(from: self)

// Attach the visitor's identity:
AwnCare.identify(AwnCareIdentity(name: "Sara", email: "[email protected]"))

تعريف الزائر

أرفِق هوية الزائر ليرى الوكلاء جهة اتصال معروفة الاسم. حدّث اللغة أو امسح الهوية عند تسجيل الخروج.

swift
AwnCare.identify(AwnCareIdentity(
  name: "Sara",
  email: "[email protected]",
  externalId: "usr_10294",
  metadata: ["plan": "pro"]
))

// Switch language or clear the identity later:
AwnCare.setLocale("en")
AwnCare.logout()

الأحداث

تفاعل مع الودجت عبر closures على النسخة المشتركة، أو بتبنّي البروتوكول AwnCareDelegate.

swift
// Observe widget events with closures…
AwnCare.onReady = { print("AwnCare ready") }
AwnCare.onUnreadCountChanged = { count in
  UIApplication.shared.applicationIconBadgeNumber = count
}
AwnCare.onChatClosed = { print("Chat closed") }

// …or conform to AwnCareDelegate:
class Support: AwnCareDelegate {
  func awnCare(_ awn: AwnCare, didChangeUnread count: Int) { /* … */ }
  func awnCareDidClose(_ awn: AwnCare) { /* … */ }
}
AwnCare.delegate = Support()

ملء الشاشة مقابل التضمين

لملء الشاشة استدعِ AwnCare.present(from:). ولتضمين المحادثة داخل تخطيطك الخاص، أضِف AwnCareChatViewController كـ view controller فرعي.

swift
// Embed the chat inside your own screen as a child view controller:
let chat = AwnCareChatViewController(
  workspaceId: "YOUR_WORKSPACE_ID",
  locale: "ar",
  color: "#2431E0"
)
addChild(chat)
chat.view.frame = container.bounds
container.addSubview(chat.view)
chat.didMove(toParent: self)

Android · كوتلن

مكتبة Android لتطبيقات Kotlin وJava، تُوزَّع عبر JitPack.

التثبيت

أضِف مستودع JitPack والاعتمادية إلى ملفات Gradle، ثم استورد care.awn.sdk.AwnCare.

kotlin
// settings.gradle.kts — add the JitPack repository:
dependencyResolutionManagement {
  repositories {
    maven { url = uri("https://jitpack.io") }
  }
}

// app/build.gradle.kts — add the dependency:
dependencies {
  implementation("com.github.awncare:awncare-android:1.0.0")
}

البدء السريع

هيّئ مرة واحدة بمعرّف مساحة العمل، ثم افتح المحادثة بملء الشاشة من سياق أي Activity أو Fragment.

kotlin
import care.awn.sdk.AwnCare
import care.awn.sdk.AwnCareIdentity

AwnCare.configure(workspaceId = "YOUR_WORKSPACE_ID", locale = "ar", color = "#2431E0")

// Launch the chat full-screen:
AwnCare.open(context)

// Attach the visitor's identity:
AwnCare.identify(AwnCareIdentity(name = "Sara", email = "[email protected]"))

تعريف الزائر

أرفِق هوية الزائر ليرى الوكلاء جهة اتصال معروفة الاسم. حدّث اللغة أو امسح الهوية عند تسجيل الخروج.

kotlin
AwnCare.identify(
  AwnCareIdentity(
    name = "Sara",
    email = "[email protected]",
    externalId = "usr_10294",
    metadata = mapOf("plan" to "pro"),
  )
)

// Switch language or clear the identity later:
AwnCare.setLocale("en")
AwnCare.logout()

الأحداث

سجّل AwnCareListener لاستقبال استدعاءات الجاهزية وعدد غير المقروء وبدء المحادثة والإغلاق.

kotlin
AwnCare.setListener(object : AwnCareListener {
  override fun onReady() { /* … */ }
  override fun onUnreadCountChanged(count: Int) {
    // update your own badge
  }
  override fun onConversationStarted(conversationId: String) { /* … */ }
  override fun onChatClosed() { /* … */ }
})

ملء الشاشة مقابل التضمين

لملء الشاشة استدعِ AwnCare.open(context). ولتضمين المحادثة في تخطيطك، ضع AwnCareChatView في ملف XML وهيّئه من الكود.

kotlin
<!-- Drop the chat into any layout: -->
<care.awn.sdk.AwnCareChatView
    android:id="@+id/awnChat"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

// Configure the embedded view from code:
findViewById<AwnCareChatView>(R.id.awnChat).apply {
  workspaceId = "YOUR_WORKSPACE_ID"
  locale = "ar"
  color = "#2431E0"
}

Flutter

إضافة Flutter مبنية على webview_flutter لنظامي iOS وAndroid من قاعدة كود Dart واحدة.

التثبيت

أضِف اعتمادية git وwebview_flutter إلى pubspec.yaml، ثم شغّل flutter pub get.

yaml
# pubspec.yaml
dependencies:
  webview_flutter: ^4.0.0
  awncare_flutter:
    git:
      url: https://github.com/awncare/awncare-flutter
      path: sdks/flutter/awncare_flutter

البدء السريع

هيّئ مرة واحدة بمعرّف مساحة العمل، ثم ادفع AwnCareChatScreen كمسار بملء الشاشة.

dart
import 'package:awncare_flutter/awncare_flutter.dart';

AwnCare.configure(workspaceId: 'YOUR_WORKSPACE_ID', locale: 'ar', color: '#2431E0');

// Push the chat as a full-screen route:
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => AwnCareChatScreen(
      onUnreadCountChanged: (count) => setState(() => unread = count),
      onClosed: () => Navigator.pop(context),
    ),
  ),
);

تعريف الزائر

أرفِق هوية الزائر ليرى الوكلاء جهة اتصال معروفة الاسم. حدّث اللغة أو امسح الهوية عند تسجيل الخروج.

dart
AwnCare.identify(const AwnCareIdentity(
  name: 'Sara',
  email: '[email protected]',
  externalId: 'usr_10294',
  metadata: {'plan': 'pro'},
));

// Switch language or clear the identity later:
AwnCare.setLocale('en');
AwnCare.logout();

الأحداث

مرّر callbacks إلى AwnCareChatScreen، أو اشترك في تدفّق AwnCareEvents العام للمعالجة على مستوى التطبيق.

dart
// Per-screen callbacks:
AwnCareChatScreen(
  onReady: () => debugPrint('ready'),
  onUnreadCountChanged: (count) => setState(() => unread = count),
  onConversationStarted: (id) => debugPrint('conversation $id'),
  onClosed: () => Navigator.pop(context),
);

// …or subscribe to the global event stream:
final sub = AwnCareEvents.stream.listen((event) {
  if (event is AwnCareUnread) setState(() => unread = event.count);
});

ملء الشاشة مقابل التضمين

لملء الشاشة ادفع AwnCareChatScreen عبر Navigator. ولتضمين المحادثة، ضع ودجت AwnCareChatView في أي مكان من شجرة الودجت.

dart
// Embed the chat inside any widget tree:
SizedBox(
  height: 480,
  child: AwnCareChatView(
    workspaceId: 'YOUR_WORKSPACE_ID',
    locale: 'ar',
    color: '#2431E0',
    onUnreadCountChanged: (count) => setState(() => unread = count),
  ),
);

React Native

مكوّن React Native مبني على react-native-webview، يُثبَّت مباشرة من GitHub.

التثبيت

ثبّت الحزمة وreact-native-webview من npm، ثم ثبّت pods الخاصة بـ iOS.

bash
npm install github:awncare/awncare-react-native react-native-webview

# iOS only — install the native pods:
cd ios && pod install

البدء السريع

اعرض مكوّن AwnCareChat بمعرّف مساحة العمل ودعه يملأ الشاشة.

tsx
import { AwnCareChat } from '@awncare/react-native';

export function SupportScreen({ navigation }) {
  const [unread, setUnread] = useState(0);
  return (
    <AwnCareChat
      workspaceId="YOUR_WORKSPACE_ID"
      locale="ar"
      color="#2431E0"
      identity={{ name: 'Sara', email: '[email protected]' }}
      onUnreadCountChanged={(c) => setUnread(c)}
      onClosed={() => navigation.goBack()}
    />
  );
}

تعريف الزائر

مرّر خاصية identity، أو تحكّم في المحادثة برمجيًا عبر ref لاستدعاء identify وsetLocale وlogout.

tsx
import { useRef } from 'react';
import { AwnCareChat, AwnCareChatRef } from '@awncare/react-native';

const ref = useRef<AwnCareChatRef>(null);

// Imperatively drive the chat through the ref:
ref.current?.identify({
  name: 'Sara',
  email: '[email protected]',
  externalId: 'usr_10294',
  metadata: { plan: 'pro' },
});
ref.current?.setLocale('en');
ref.current?.logout();

<AwnCareChat ref={ref} workspaceId="YOUR_WORKSPACE_ID" />;

الأحداث

عالج الأحداث عبر الخصائص onReady وonUnreadCountChanged وonConversationStarted وonMessageReceived وonClosed.

tsx
<AwnCareChat
  workspaceId="YOUR_WORKSPACE_ID"
  onReady={() => console.log('ready')}
  onUnreadCountChanged={(count) => setUnread(count)}
  onConversationStarted={(id) => console.log('conversation', id)}
  onMessageReceived={({ text, sender }) => console.log(sender, text)}
  onClosed={() => navigation.goBack()}
/>

ملء الشاشة مقابل التضمين

AwnCareChat مجرّد View — اعرضه بملء الشاشة، أو داخل أي حاوية محدّدة الأبعاد لتضمينه.

tsx
// <AwnCareChat> is just a View — render it inside any container:
<View style={{ height: 480, borderRadius: 16, overflow: 'hidden' }}>
  <AwnCareChat workspaceId="YOUR_WORKSPACE_ID" locale="ar" color="#2431E0" />
</View>

الجسر والأحداث

يقوم عقد الأحداث نفسه خلف كل حزمة. في الخلفية، تتبادل الصفحة المستضافة وكودك الأصيل الرسائل عبر هذا الجسر.

الأحداث الصادرة من الودجت

تُرسِل صفحة المحادثة المستضافة هذه الأحداث إلى الطبقة الأصيلة. وتقدّمها كل حزمة على شكل callbacks أو delegates أو listeners بأسلوب المنصة.

الحدثالحمولةالوصف
ready—اكتمل تحميل صفحة المحادثة وأصبحت جاهزة للاستخدام.
open—فُتحت نافذة المحادثة.
close—أُغلقت نافذة المحادثة — أغلِق الشاشة أو امسح الشارة.
unread{ count }تغيّر عدد الرسائل غير المقروءة — حدّث شارة تطبيقك أو أيقونته.
conversation:started{ conversationId }أُنشئت محادثة جديدة.
message:received{ text, sender }وصلت رسالة من وكيل أو بوت؛ وقيمة sender إمّا "agent" أو "bot".
json
// The hosted chat page posts these events to the native layer:
{ "type": "ready" }
{ "type": "open" }
{ "type": "close" }
{ "type": "unread", "count": 3 }
{ "type": "conversation:started", "conversationId": "cnv_8f2a" }
{ "type": "message:received", "text": "How can I help?", "sender": "agent" }

واجهة AwnCareMobile

يتحكّم الكود الأصيل في الودجت باستدعاء واجهة JavaScript هذه المحقونة في الـ WebView. وتغلّف كل حزمة هذه الاستدعاءات بطرق أصيلة فنادرًا ما تلمس الجسر مباشرة.

الحقلالنوعالوصف
identify(identity)→ voidإرفاق أو تحديث هوية الزائر (الاسم والبريد والمعرّف الخارجي والبيانات الإضافية).
setLocale(locale)"ar" | "en"تبديل لغة واجهة الودجت أثناء التشغيل.
logout()→ voidمسح هوية الزائر الحالية لبدء جلسة جديدة.
open()→ voidفتح نافذة المحادثة برمجيًا.
js
// Native drives the widget by calling the injected AwnCareMobile API:
AwnCareMobile.identify({ name: "Sara", email: "[email protected]" });
AwnCareMobile.setLocale("en");   // "ar" | "en"
AwnCareMobile.logout();
AwnCareMobile.open();

الإشعارات (Push)

نبّه الزوّار على هواتفهم عندما يردّ موظف أو روبوت والتطبيق مغلق — باستخدام مشروع Firebase الخاص بك.

البنية — أحضِر مشروع Firebase الخاص بك

لا يضمّن AwnCare مكتبة Firebase إطلاقًا. يُحضِر مالك التطبيق مشروع Firebase الخاص به ويلصق ملف JSON لحساب الخدمة في التكاملات. تُمرّر حزم SDK للجوال رموز الأجهزة المرتبطة بالزائر الحالي، ويرسل خادم AwnCare الإشعار عبر واجهة FCM HTTP v1 كلما ردّ موظف أو روبوت على زائر غير متصل.

بما أنّك تملك مشروع Firebase، يبقى التسليم والحصص وشهادات APNs تحت سيطرتك بالكامل. لا يحتفظ AwnCare سوى ببيانات اعتماد حساب الخدمة ورموز الأجهزة التي يمرّرها تطبيقك إليه.

إعداد مساحة العمل

من لوحة التحكم، افتح التكاملات ← «الإشعارات (FCM)»، ثم الصق ملف JSON لحساب خدمة Firebase واضغط اتصال. يُختبَر الاتصال قبل الحفظ، ويظهر معرّف المشروع المُستخرَج على البطاقة.

تمرير رموز الأجهزة ومعالجة النقر

في كل تطبيق، مرّر رمز جهاز FCM إلى AwnCare عبر setPushToken (الآن ومع كل تحديث)، وافتح المحادثة عند نقر المستخدم على الإشعار. يصل معرّف المحادثة في data.conversationId.

iOS · سويفت

اجلب الرمز من FirebaseMessaging ومرّره؛ وعالِج النقر في مفوّض UNUserNotificationCenter.

swift
import FirebaseMessaging
import UserNotifications

// 1. Hand the current FCM token to AwnCare — and again on every refresh:
Messaging.messaging().token { token, _ in
  if let token { AwnCare.setPushToken(token) }
}

func messaging(_ messaging: Messaging, didReceiveRegistrationToken token: String?) {
  if let token { AwnCare.setPushToken(token) }
}

// 2. Open the conversation when the user taps the notification:
func userNotificationCenter(
  _ center: UNUserNotificationCenter,
  didReceive response: UNNotificationResponse,
  withCompletionHandler completionHandler: @escaping () -> Void
) {
  let info = response.notification.request.content.userInfo
  if let conversationId = info["conversationId"] as? String {
    // conversationId is available if you need to deep-link a specific thread.
    AwnCare.present(from: rootViewController)
  }
  completionHandler()
}

Android · كوتلن

مرّر الرمز من FirebaseMessagingService.onNewToken، وأنشئ إشعارك الخاص الذي يفتح المحادثة عند النقر.

kotlin
class AppMessagingService : FirebaseMessagingService() {

  // 1. Hand every new token to AwnCare:
  override fun onNewToken(token: String) {
    AwnCare.setPushToken(token)
  }

  // 2. Post a notification whose tap opens the AwnCare chat:
  override fun onMessageReceived(msg: RemoteMessage) {
    if (msg.data["type"] != "awncare_message") return
    val conversationId = msg.data["conversationId"] ?: return

    val intent = Intent(this, MainActivity::class.java).apply {
      putExtra("awncare_conversationId", conversationId)
    }
    val pending = PendingIntent.getActivity(
      this, conversationId.hashCode(), intent,
      PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
    )

    val notification = NotificationCompat.Builder(this, "awncare")
      .setContentTitle(msg.notification?.title ?: msg.data["title"])
      .setContentText(msg.notification?.body ?: msg.data["body"])
      .setSmallIcon(R.drawable.ic_chat)
      .setContentIntent(pending)
      .setAutoCancel(true)
      .build()

    NotificationManagerCompat.from(this)
      .notify(conversationId.hashCode(), notification)
  }
}

// In the Activity opened by the tap:
AwnCare.open(context)

Flutter

مرّر getToken() و onTokenRefresh؛ وافتح شاشة المحادثة من onMessageOpenedApp.

dart
import 'package:firebase_messaging/firebase_messaging.dart';

// 1. Hand the token to AwnCare — now and on every refresh:
FirebaseMessaging.instance.getToken().then((t) {
  if (t != null) AwnCare.setPushToken(t);
});
FirebaseMessaging.instance.onTokenRefresh.listen(AwnCare.setPushToken);

// 2. Open the conversation when a notification is tapped:
FirebaseMessaging.onMessageOpenedApp.listen((m) {
  if (m.data['type'] != 'awncare_message') return;
  final conversationId = m.data['conversationId'];
  Navigator.push(
    context,
    MaterialPageRoute(builder: (_) => const AwnCareChatScreen()),
  );
});

React Native

مرّر messaging().getToken() إلى مرجع المحادثة، وتنقّل من onNotificationOpenedApp.

tsx
import messaging from '@react-native-firebase/messaging';
import { useEffect, useRef } from 'react';
import { AwnCareChat, AwnCareChatRef } from '@awncare/react-native';

const chatRef = useRef<AwnCareChatRef>(null);

useEffect(() => {
  // 1. Hand the token to AwnCare — now and on every refresh:
  (async () => {
    const token = await messaging().getToken();
    chatRef.current?.setPushToken(token);
  })();
  const unsubscribe = messaging().onTokenRefresh((token) => {
    chatRef.current?.setPushToken(token);
  });

  // 2. Navigate to the chat when a notification opens the app:
  messaging().onNotificationOpenedApp((rm) => {
    if (rm.data?.type !== 'awncare_message') return;
    const conversationId = rm.data?.conversationId;
    // navigate to your <AwnCareChat> screen, optionally using conversationId
  });

  return unsubscribe;
}, []);

<AwnCareChat ref={chatRef} workspaceId="YOUR_WORKSPACE_ID" />;
مكتبة Firebase نفسها من مسؤولية التطبيق المضيف — لا يضمّنها AwnCare أبدًا. يُهيّئ تطبيقك Firebase و APNs، ويكتفي بتمرير الرمز إلينا عبر setPushToken.

عقد الحمولة (Payload)

كل إشعار يرسله AwnCare يتّبع هذا الشكل. جميع قيم data نصوص.

الحقلالقيمة
notification.titleاسم مساحة العمل الخاصة بك.
notification.bodyنص الردّ — مع إزالة تنسيق Markdown واقتطاعه إلى 120 حرفًا.
data.conversationIdمعرّف المحادثة التي ستُفتح عند النقر على الإشعار.
data.typeدائمًا النص الحرفي "awncare_message" — استخدمه لاكتشاف إشعارات AwnCare.