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

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

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

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

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

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

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

تحسينات الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات)

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

تحسينات Android 12 (المستوى 31 لواجهة برمجة التطبيقات)

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

  • على الأجهزة التي تعمل بنظام Android 12 (المستوى 31 لواجهة برمجة التطبيقات) أو إصدار أحدث، يمكنك استخدام الدالة المخصّصة للرجوع onServiceLost() للتنبيه عند فقدان تطبيقك لخدمة تم رصدها بسبب stopped التوقف عن العمل أو الخروج من النطاق.
  • تم تبسيط إعداد مسارات البيانات في ميزة "الوصول إلى Wi-Fi". كانت الإصدارات السابقة تستخدم رسائل L2 لتوفير عنوان MAC للمشغِّل، ما كان يؤدي إلى إدخال وقت استجابة. على الأجهزة التي تعمل بالإصدار 12 من نظام التشغيل Android والإصدارات الأحدث، يمكن ضبط المُجيب (الخادم) لقبول أي جهاز متوافق، أي أنّه لا يحتاج إلى معرفة عنوان 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" متاحة حاليًا، يُرجى الاتصال بالرقم 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"، يجب أن يحصل تطبيقك على 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. عند حدوث ذلك، ينفذ النظام أسلوب callback 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 Aware على جهاز المشترك باستخدام الطريقة نفسها المستخدَمة على جهاز الناشر. الإجراءات المستحسنة عدم تحديد منفذ عند إنشاء 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 API إمكانية الانتقال مباشرةً إلى نظير Wi-Fi Aware باستخدام عنوان MAC أو PeerHandle.

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

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

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

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

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

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

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