نظرة عامة على Wi-Fi Aware

تتيح إمكانات Wi-Fi Aware الأجهزة التي تعمل بنظام التشغيل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) و أعلى من الوصول إلى بعضهم البعض والتواصل مباشرةً دون أي نوع آخر بالاتصال بينهما. يُعرف Wi-Fi Aware أيضًا باسم اتصال مباشر بمحطات لاسلكية مجاورة (NAN).

تعمل ميزة "الشبكات المزوّدة بتقنية Wi-Fi Aware" من خلال تشكيل مجموعات مع الأجهزة المجاورة، أو من خلال إنشاء مجموعة جديدة إذا كان الجهاز هو الجهاز الأول في منطقة معيّنة. هذا النمط ينطبق سلوك التجميع على الجهاز بالكامل وتتم إدارته بواسطة شبكة Wi-Fi خدمة النظام الواعية؛ ولا تتحكم التطبيقات في سلوك التجميع العنقودي. استخدام التطبيقات واجهات برمجة التطبيقات لخدمة Wi-Fi Aware API للاتصال بخدمة نظام Wi-Fi Aware، التي تدير أجهزة Wi-Fi المزوّدة بخدمة Wi-Fi على الجهاز.

تتيح واجهات برمجة التطبيقات Wi-Fi Aware APIs للتطبيقات تنفيذ العمليات التالية:

  • اكتشاف الأجهزة الأخرى: توفّر واجهة برمجة التطبيقات آلية للعثور على الأجهزة الأخرى. الأجهزة المجاورة. تبدأ العملية عند نشر أحد الأجهزة أو خدمات أخرى قابلة للاكتشاف بعد ذلك، عندما يشترك جهاز في خدمة واحدة أو أكثر ويدخل في نطاق شبكة Wi-Fi الخاصة بالناشر، يتلقّى المشترك إعلامًا يفيد باكتشاف ناشر مطابق. بعد عندما يكتشف المشترك ناشرًا، فيمكن للمشترك إما إرسال فيديو قصير أو إنشاء اتصال بالشبكة مع الجهاز الذي تم اكتشافه. ويمكن أن تتضمّن الأجهزة ناشرين ومشتركين في آنٍ واحد.

  • إنشاء اتصال شبكة: بعد اكتشاف جهازين لكل منهما الآخرين، يمكنهم إنشاء اتصال شبكة Wi-Fi ثنائي الاتجاه بدون نقطة وصول.

توفّر اتصالات شبكة Wi-Fi Aware معدّلات نقل بيانات أعلى على مسافات أطول مقارنةً باتصالات البلوتوث . هذه الأنواع من الاتصالات مفيدة للتطبيقات التي تشارك ملفات كبيرة كميات البيانات بين المستخدمين، مثل تطبيقات مشاركة الصور.

تحسينات Android 13 (المستوى 33)

على الأجهزة التي تعمل بنظام التشغيل Android 13 (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث التي تتيح البحث الفوري التواصل، يمكن للتطبيقات استخدام PublishConfig.Builder.setInstantCommunicationModeEnabled() و SubscribeConfig.Builder.setInstantCommunicationModeEnabled() طريقة من أجل تفعيل وضع الاتصال الفوري أو إيقافه للناشر أو المشترك جلسة الاستكشاف. يساعد وضع التواصل الفوري في تسريع عملية تبادل الرسائل واكتشاف الخدمة وأي مسار بيانات تم إعداده كجزء من حساب الناشر أو المشترك جلسة الاستكشاف. لتحديد ما إذا كان الجهاز يتيح ميزة "التواصل الفوري"، استخدِم طريقة isInstantCommunicationModeSupported().

تحسينات Android 12 (المستوى 31)

يضيف نظام التشغيل Android 12 (المستوى 31 لواجهة برمجة التطبيقات) بعض التحسينات على ميزة "الاستشعار بشبكة Wi-Fi":

  • على الأجهزة التي تعمل بنظام التشغيل Android 12 (المستوى 31 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك استخدام onServiceLost() معاودة الاتصال ليتم تنبيهك عندما يفقد تطبيقك إحدى الخدمات التي تم اكتشافها بسبب تتوقف الخدمة أو تنتقل خارج النطاق.
  • تم تبسيط إعداد مسارات البيانات في ميزة "الوصول إلى Wi-Fi". كانت الإصدارات السابقة تستخدم رسائل L2 لتوفير عنوان MAC للمشغِّل، ما كان يؤدي إلى إدخال وقت استجابة. على الأجهزة التي تعمل بنظام التشغيل Android 12 والإصدارات الأحدث، سيجيب المجيب (الخادم) لقبول أي نظير؛ أي أنه لا يحتاج إلى معرفة عنوان MAC لمنشئ التفعيل مقدمًا. ويؤدي ذلك إلى تسريع عملية بدء مسار البيانات ويسمح بإنشاء روابط متعددة بين نقطتَين باستخدام طلب شبكة واحد فقط.
  • يمكن للتطبيقات التي تعمل بنظام التشغيل Android 12 أو الإصدارات الأحدث استخدام WifiAwareManager.getAvailableAwareResources() للحصول على عدد مسارات البيانات المتاحة حاليًا وجلسات نشر الجلسات والاشتراك في الجلسات يمكن أن يساعد هذا التطبيق في تحديد ما إذا كانت هناك الموارد المتاحة الكافية لتنفيذ وظائفها المطلوبة.

الإعداد الأولي

لإعداد تطبيقك لاستخدام ميزتَي الاكتشاف والربط عبر Wi-Fi Aware، عليك اتّباع الخطوات التالية:

  1. اطلب الأذونات التالية في ملف بيان تطبيقك:

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- If your app targets Android 13 (API level 33)
         or higher, you must declare the NEARBY_WIFI_DEVICES permission. -->
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                     <!-- If your app derives location information from
                          Wi-Fi APIs, don't include the "usesPermissionFlags"
                          attribute. -->
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     <!-- If any feature in your app relies on precise location
                          information, don't include the "maxSdkVersion"
                          attribute. -->
                     android:maxSdkVersion="32" />
  2. تحقَّق مما إذا كان الجهاز متوافقًا مع ميزة Wi-Fi Aware باستخدام واجهة برمجة التطبيقات PackageManager ، كما هو موضّح أدناه:

    Kotlin

    context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)

    Java

    context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
  3. تحقَّق مما إذا كانت ميزة "الاستشعار بالشبكات Wi-Fi" متاحة حاليًا. قد تتوفّر خدمة Wi-Fi Aware في الجهاز، ولكن قد لا يكون متاحًا حاليًا لأنّ المستخدم أوقفه شبكة Wi-Fi أو الموقع الجغرافي. وحسب إمكانيات الأجهزة والبرامج الثابتة، يمكن لبعض الأجهزة قد لا يتوافق هذا الإعداد مع خدمة Wi-Fi Aware في حال تفعيل اتصال Wi-Fi المباشر أو SoftAP أو التوصيل. استخدامها. للتحقّق مما إذا كانت خدمة Wi-Fi Aware متوفّرة حاليًا، يُرجى الاتصال isAvailable()

    قد يتغير مدى توفّر خدمة Wi-Fi Aware في أي وقت. يجب أن يُسجِّل تطبيقك BroadcastReceiver لتلقّي ACTION_WIFI_AWARE_STATE_CHANGED، الذي يتم إرساله عند تغيير مدى التوفّر. عندما يتلقّى تطبيقك intent بث المحتوى، من المفترض أن يتخلّص من جميع الجلسات الحالية (على افتراض أنّه تم إيقاف خدمة Wi-Fi Aware)، ثم يتحقّق من الحالة الراهنة للمدى المتوفّر ويضبط سلوكه وفقًا لذلك. مثلاً:

    Kotlin

    val wifiAwareManager = context.getSystemService(Context.WIFI_AWARE_SERVICE) as WifiAwareManager?
    val filter = IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED)
    val myReceiver = object : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            // discard current sessions
            if (wifiAwareManager?.isAvailable) {
                ...
            } else {
                ...
            }
        }
    }
    context.registerReceiver(myReceiver, filter)

    Java

    WifiAwareManager wifiAwareManager = 
            (WifiAwareManager)context.getSystemService(Context.WIFI_AWARE_SERVICE)
    IntentFilter filter =
            new IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED);
    BroadcastReceiver myReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // discard current sessions
            if (wifiAwareManager.isAvailable()) {
                ...
            } else {
                ...
            }
        }
    };
    context.registerReceiver(myReceiver, filter);

لمزيد من المعلومات، يُرجى الاطّلاع على عمليات البث.

الحصول على جلسة

لبدء استخدام خدمة Wi-Fi Aware، يجب أن يحصل تطبيقك على WifiAwareSession عن طريق الاتصال attach() هذه الطريقة بإجراء ما يلي:

  • تفعيل الأجهزة المزوّدة بتقنية Wi-Fi Aware
  • الانضمام إلى مجموعة Wi-Fi Aware أو تشكيلها
  • تنشئ جلسة Wi-Fi Aware باستخدام مساحة اسم فريدة تعمل كحاوية لجميع جلسات الاكتشاف التي تم إنشاؤها فيها.

إذا تم إرفاق التطبيق بنجاح، ينفِّذ النظام معاودة الاتصال "onAttached()" توفر معاودة الاتصال هذه كائن WifiAwareSession التي ينبغي أن يستخدمها التطبيق في جميع العمليات الإضافية للجلسة. يمكن لأي تطبيق استخدام لنشر خدمة أو الاشتراك في خدمة

يجب أن يتصل التطبيق attach() مرة واحدة فقط. في حال حذف يطلب تطبيقك الاتصال بـ attach(). يتلقى التطبيق جلسة مختلفة لكل مكالمة، على أن يكون مساحة الاسم الخاصة بها. قد يكون ذلك مفيدًا في السيناريوهات المعقّدة، ولكن يجب عمومًا تجنُّبه.

نشر خدمة

لجعل الخدمة قابلة للاكتشاف، اتصل بـ طريقة publish()، التي يأخذ المعلمات التالية:

  • PublishConfig يحدّد اسم الخدمة وخصائص الضبط الأخرى، مثل فلتر المطابقة.
  • DiscoverySessionCallback لتحديد الإجراءات التي سيتم تنفيذها عند حدوث الأحداث، مثل عندما يتلقّى المشترك رسالة

وفي ما يلي مثال لذلك:

Kotlin

val config: PublishConfig = PublishConfig.Builder()
        .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
        .build()
awareSession.publish(config, object : DiscoverySessionCallback() {

    override fun onPublishStarted(session: PublishDiscoverySession) {
        ...
    }

    override fun onMessageReceived(peerHandle: PeerHandle, message: ByteArray) {
        ...
    }
})

Java

PublishConfig config = new PublishConfig.Builder()
    .setServiceName(Aware_File_Share_Service_Name)
    .build();

awareSession.publish(config, new DiscoverySessionCallback() {
    @Override
    public void onPublishStarted(PublishDiscoverySession session) {
        ...
    }
    @Override
    public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
        ...
    }
}, null);

إذا نجحت عملية النشر، سيتم onPublishStarted() استدعاء طريقة معاودة الاتصال.

بعد النشر، عندما تنتقل الأجهزة التي تعمل تطبيقات مطابقة مع المشتركين إلى نطاق Wi-Fi لجهاز النشر، يكتشف المشتركون الخدمة. فعندما اكتشاف مشترك لناشر، فلن يحصل الناشر على إشعار إذا أرسل المشترك رسالة إلى الناشر، إرسال إشعار إلى الناشر عند حدوث ذلك، onMessageReceived() استدعاء طريقة معاودة الاتصال. يمكنك استخدام صفحة PeerHandle من هذه الطريقة إلى يمكنك إرسال رسالة ردًا إلى المشترك أو أنشئ رابطًا بها.

لإيقاف نشر الخدمة، يُرجى الاتصال DiscoverySession.close() ترتبط جلسات الاكتشاف مع الوالدين WifiAwareSession إذا كانت الجلسة الرئيسية مغلق، يتم أيضًا إغلاق جلسات الاكتشاف المرتبطة به. وفي حين أنّه يتم إغلاق العناصر المهملة أيضًا، لا يضمن النظام إغلاق جلسات خارج النطاق، لذا ننصحك باستدعاء close() methods بشكل صريح.

الاشتراك في خدمة

للاشتراك في خدمة، يمكنك استدعاء subscribe()، والتي تأخذ المَعلمات التالية:

  • SubscribeConfig يحدِّد اسم الخدمة المطلوب الاشتراك فيها وخصائص الضبط الأخرى، مثل فلتر المطابقة.
  • يحدد DiscoverySessionCallback الإجراءات التي يتم تنفيذها عند وقوع الأحداث، مثل اكتشاف ناشرٍ ما.

وفي ما يلي مثال لذلك:

Kotlin

val config: SubscribeConfig = SubscribeConfig.Builder()
        .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
        .build()
awareSession.subscribe(config, object : DiscoverySessionCallback() {

    override fun onSubscribeStarted(session: SubscribeDiscoverySession) {
        ...
    }

    override fun onServiceDiscovered(
            peerHandle: PeerHandle,
            serviceSpecificInfo: ByteArray,
            matchFilter: List<ByteArray>
    ) {
        ...
    }
}, null)

Java

SubscribeConfig config = new SubscribeConfig.Builder()
    .setServiceName("Aware_File_Share_Service_Name")
    .build();

awareSession.subscribe(config, new DiscoverySessionCallback() {
    @Override
    public void onSubscribeStarted(SubscribeDiscoverySession session) {
        ...
    }

    @Override
    public void onServiceDiscovered(PeerHandle peerHandle,
            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
        ...
    }
}, null);

إذا نجحت عملية الاشتراك، فسيطلب النظام onSubscribeStarted() في تطبيقك. لأنه يمكنك استخدام الوسيطة SubscribeDiscoverySession في للتواصل مع أحد الناشرين بعد اكتشاف تطبيقك لأحد الناشرين، يجب أن يحفظ هذا المرجع. يمكنك تحديث جلسة الاشتراك في أي وقت من خلال يتصل updateSubscribe() حول جلسة الاكتشاف.

في هذه المرحلة، ينتظر اشتراكك اشتراك الناشرين المطابقين. نطاق Wi-Fi. وعندما يحدث ذلك، ينفذ النظام onServiceDiscovered() . يمكنك استخدام PeerHandle. من معاودة الاتصال هذه لإرسال رسالة أو أنشئ اتصالاً بهذا الناشر.

لإيقاف الاشتراك في خدمة، يُرجى الاتصال DiscoverySession.close() ترتبط جلسات "الاقتراحات" بجلسة الوالد WifiAwareSession. إذا كانت الجلسة الرئيسية مغلق، يتم أيضًا إغلاق جلسات الاكتشاف المرتبطة به. خلال فترة التجاهل الأجسام مغلقة أيضًا، فلا يضمن النظام أن تكون خارج النطاق الجلسات مغلقة، لذلك ننصحك بالاتصال بـ close() صراحةً الطرق.

إرسال رسالة

لإرسال رسالة إلى جهاز آخر، تحتاج إلى العناصر التالية:

لإرسال رسالة، يُرجى الاتصال sendMessage() قد تحدث بعد ذلك عمليات معاودة الاتصال التالية:

  • عندما يتلقّى الجهاز المعني الرسالة بنجاح، يستدعي النظام onMessageSendSucceeded() دالة ردّ الاتصال في تطبيق الإرسال.
  • عندما يتلقّى التطبيق المشابه رسالة، يستدعي النظام onMessageReceived() دالة الاستدعاء في تطبيق الاستلام.

على الرغم من أنّ PeerHandle مطلوب للتواصل مع التطبيقات المشابهة، يجب عدم الاعتماد عليه كمعرّف دائم للتطبيقات المشابهة. يمكن للتطبيق استخدام المعرّفات ذات المستوى الأعلى، والتي تكون مضمّنة في خدمة الاكتشاف نفسها أو في الرسائل اللاحقة. يمكنك تضمين معرّف في خدمة الاكتشاف مع الـ setMatchFilter() أو setServiceSpecificInfo() طريقة PublishConfig أو SubscribeConfig. تشير رسالة الأشكال البيانية تؤثر طريقة setMatchFilter() في الاكتشاف، في حين أن لا تؤثر طريقة setServiceSpecificInfo() في إمكانية الاكتشاف.

يتضمن تضمين معرّف في رسالة تعديل مصفوفة بايت الرسالة إلى تضمين معرّف (على سبيل المثال، كأول بضع وحدات بايت).

إنشاء عملية ربط

تتيح تقنية Wi-Fi Aware إمكانية التواصل بين جهازَين مزوّدين بتقنية Wi-Fi Aware.

لإعداد اتصال خادم العميل:

  1. يمكنك استخدام ميزة "اكتشاف Wi-Fi" من أجل نشر خدمة (على الخادم) والاشتراك في خدمة (على العميل).

  2. بعد أن يكتشف المشترك الناشر إرسال رسالة من المشترك إلى الناشر

  3. ابدأ تشغيل ServerSocket على جهاز الناشر واضبط منفذ الربط أو احصل عليه:

    Kotlin

    val ss = ServerSocket(0)
    val port = ss.localPort

    Java

    ServerSocket ss = new ServerSocket(0);
    int port = ss.getLocalPort();
  4. استخدِم ConnectivityManager لطلب شبكة Wi-Fi Aware على الناشر باستخدام WifiAwareNetworkSpecifier، مع تحديد جلسة الاكتشاف وPeerHandle للمشترك، والتي حصلت عليها من الرسالة التي أرسلها المشترك:

    Kotlin

    val networkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
        .setPskPassphrase("somePassword")
        .setPort(port)
        .build()
    val myNetworkRequest = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
        .setNetworkSpecifier(networkSpecifier)
        .build()
    val callback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            ...
        }
    
        override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
            ...
        }
    
        override fun onLost(network: Network) {
            ...
        }
    }
    
    connMgr.requestNetwork(myNetworkRequest, callback);

    Java

    NetworkSpecifier networkSpecifier = new WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
        .setPskPassphrase("somePassword")
        .setPort(port)
        .build();
    NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
        .setNetworkSpecifier(networkSpecifier)
        .build();
    ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            ...
        }
    
        @Override
        public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
            ...
        }
    
        @Override
        public void onLost(Network network) {
            ...
        }
    };
    
    ConnectivityManager connMgr.requestNetwork(myNetworkRequest, callback);
  5. بعد أن يطلب الناشر شبكة، يجب أن يتم إرسال رسالة إلى المشترك.

  6. بعد أن يتلقّى المشترك الرسالة من الناشر، يمكنك طلب شبكة Wi-Fi. الشبكة الواعية للمشتركين باستخدام نفس الطريقة المتبعة على الناشر. الإجراءات المستحسنة عدم تحديد منفذ عند إنشاء NetworkSpecifier يتم استدعاء methods المناسبة للرجوع عند توفُّر اتصال الشبكة أو تغييره أو فقدانه.

  7. بعد استدعاء طريقة onAvailable() إلى المشترك، يتوفّر العنصر Network مع ويمكنك فتح Socket للتواصل معه مع ServerSocket على الناشر، ولكن عليك أن تعرف عنوان IPv6 الخاص بـ ServerSocket ومنفذه. تحصل على هذه من كائن NetworkCapabilities الواردة في معاودة الاتصال على onCapabilitiesChanged():

    Kotlin

    val peerAwareInfo = networkCapabilities.transportInfo as WifiAwareNetworkInfo
    val peerIpv6 = peerAwareInfo.peerIpv6Addr
    val peerPort = peerAwareInfo.port
    ...
    val socket = network.getSocketFactory().createSocket(peerIpv6, peerPort)

    Java

    WifiAwareNetworkInfo peerAwareInfo = (WifiAwareNetworkInfo) networkCapabilities.getTransportInfo();
    Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
    int peerPort = peerAwareInfo.getPort();
    ...
    Socket socket = network.getSocketFactory().createSocket(peerIpv6, peerPort);
  8. عند الانتهاء من الاتصال بالشبكة، اتصل بالرقم unregisterNetworkCallback().

تصنيف التطبيقات المشابهة والاكتشاف المستند إلى الموقع الجغرافي

جهاز يتضمّن موقعًا جغرافيًا لميزة "مراسلة نصية في الوقت الفعلي" لشبكة Wi-Fi للقدرات يمكنها قياس المسافة مباشرة مع النظراء واستخدام هذه المعلومات حصر إمكانية اكتشاف خدمة Wi-Fi Aware.

تسمح واجهة برمجة التطبيقات Wi-Fi RTT بتحديد المسافة مباشرةً إلى جهاز متوافق مع Wi-Fi Aware باستخدام إما عنوان MAC أو PeerHandle.

يمكن تقييد اكتشاف Wi-Fi من خلال اكتشاف الخدمات داخل الحدود الجغرافية على وجه الخصوص. على سبيل المثال، يمكنك إعداد حدود جغرافية تتيح اكتشاف المحتوى. لجهاز ينشر خدمة "Aware_File_Share_Service_Name" غير أقرب من 3 أمتار (المحددة على أنها 3000 ملم) ولا تزيد عن 10 أمتار (تم تحديده على أنّه 10000 ملم).

لتفعيل وضع حدود جغرافية، على كل من الناشر والمشترك اتخاذ الإجراءين التاليين:

  • على الناشر تفعيل ميزة تحديد المسافة في الخدمة المنشورة باستخدام الإجراء setRangingEnabled(true).

    إذا لم يفعّل الناشر ميزة تحديد المسافة، سيتم تجاهل أي قيود حدود جغرافية حدّدها المشترك وسيتم إجراء عملية الاكتشاف العادية، بغض النظر عن المسافة.

  • على المشترك تحديد حدود جغرافية باستخدام بعض المجموعات من setMinDistanceMm و setMaxDistanceMm.

    بالنسبة لأي من القيمتين، لا تعني المسافة غير المحددة أي حد. التحديد فقط فإن الحد الأقصى للمسافة يعني ألا تقل المسافة عن 0. يمكن فقط تحديد الحد الأدنى للمسافة لا يتضمن حدًا أقصى.

عندما يتم اكتشاف خدمة نظير داخل سياج جغرافي، onServiceDiscoveredWithinRange يتم تشغيل معاودة الاتصال، والتي توفر المسافة التي تم قياسها للنظير. يمكن بعد ذلك استخدام واجهة برمجة التطبيقات Wi-Fi RTT المباشرة حسب الحاجة لقياس المسافة في مواعيد لاحقة.