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

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

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

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

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

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

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

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

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

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

يضيف الإصدار Android 12 (المستوى 31 من واجهة برمجة التطبيقات) بعض التحسينات إلى خدمة Wi-Fi Aware:

  • على الأجهزة التي تعمل بنظام التشغيل 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 Aware متاحة حاليًا. قد تتوفّر خدمة Wi-Fi Aware في الجهاز، ولكن قد لا يكون متاحًا حاليًا لأنّ المستخدم أوقفه شبكة Wi-Fi أو الموقع الجغرافي. وحسب إمكانيات الأجهزة والبرامج الثابتة، يمكن لبعض الأجهزة قد لا يتوافق هذا الإعداد مع خدمة Wi-Fi Aware في حال تفعيل اتصال Wi-Fi المباشر أو SoftAP أو التوصيل. استخدامها. للتحقّق مما إذا كانت خدمة Wi-Fi Aware متوفّرة حاليًا، يُرجى الاتصال isAvailable()

    قد يتغير مدى توفّر خدمة Wi-Fi Aware في أي وقت. يجب أن سجِّل "BroadcastReceiver" لتلقّي ACTION_WIFI_AWARE_STATE_CHANGED, والذي يتم إرساله عند تغير مدى التوفر. عندما يتلقّى تطبيقك حسب النية بالشراء، يجب أن يتجاهل جميع الجلسات الحالية (مع افتراض أن انقطعت خدمة 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() صراحةً الطرق.

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

للاشتراك في خدمة، يُرجى الاتصال طريقة واحدة (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.

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

  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 تشير رسالة الأشكال البيانية طرق معاودة الاتصال المناسبة عندما يتم أو تغييرها أو فقدانها.

  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 API إمكانية الانتقال مباشرةً إلى نظير Wi-Fi Aware باستخدام عنوان MAC أو PeerHandle.

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

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

  • يجب على الناشر تفعيل النطاق في الخدمة المنشورة باستخدام setRangingEnabled(true)

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

  • يجب أن يحدد المشترك سياجًا جغرافيًا باستخدام مجموعة من setMinDISTANCEMm أو setMaxSpaceMm.

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

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