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

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

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

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

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

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

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

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

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

    يمكن أن يتغيّر مدى توفّر ميزة "الاستشعار بالشبكات Wi-Fi" في أي وقت. يجب أن يُسجِّل تطبيقك 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"، يجب أن يحصل تطبيقك على WifiAwareSession من خلال الاتصالattach(). تؤدي هذه الطريقة المهام التالية:

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

في حال إرفاق التطبيق بنجاح، ينفذ النظام أسلوب callback 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);

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

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

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

إرسال رسالة

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

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

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

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

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

إنشاء اتصال

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

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

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

  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().

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

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

تسمح واجهة برمجة التطبيقات Wi-Fi RTT بتحديد المسافة مباشرةً إلى جهاز متوافق مع 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 المباشرة حسب الحاجة لقياس المسافة في مواعيد لاحقة.