סקירה כללית על Wi-Fi Aware

יכולות של מודעות ל-Wi-Fi מאפשרות למכשירים שפועלת בהם גרסת Android 8.0 (רמת API 26) וגם גבוה יותר כדי לגלות זה את זה ולהתחבר ישירות זה לזה ללא שום סוג אחר של את הקישוריות ביניהם. המודעות ל-Wi-Fi נקראת גם מוּדעוּת בסביבה Networking (NAN).

רשתות מודעות ל-Wi-Fi פועלות על ידי יצירת אשכולות עם מכשירים קרובים, או באמצעות יצירת אשכול חדש, אם המכשיר הוא הראשון באזור. הזה הקיבוץ באשכולות חל על כל המכשיר ומנוהל באמצעות ה-Wi-Fi שירות מערכת ידוע; לאפליקציות אין שליטה על ההתנהגות של אשכולות. שימוש באפליקציות את ממשקי ה-API של מודעות ל-Wi-Fi כדי לדבר עם שירות מערכת המודעות ל-Wi-Fi, שמנהל חומרת Wi-Fi Aware במכשיר.

ממשקי ה-API של מודעות ל-Wi-Fi מאפשרים לאפליקציות לבצע את הפעולות הבאות:

  • גילוי מכשירים אחרים: ל-API יש מנגנון למציאת מכשירים אחרים של מכשירים בקרבת מקום. התהליך מתחיל כשמכשיר אחד מפרסם אחד או שירותים נוספים לגילוי. לאחר מכן, כשמכשיר יירשם לערוץ אחד או יותר ונכנס לטווח ה-Wi-Fi של בעל האתר, המנוי מקבל התראה על כך שנמצא בעל אתר תואם. אחרי המנוי מגלה בעל אתר, והמנוי יכול לשלוח סרטון Shorts או ליצור חיבור לרשת עם המכשיר שאותר. המכשירים יכולים להיות בו-זמנית גם בעלי תוכן דיגיטלי וגם מנויים.

  • יצירת חיבור לרשת: אחרי ששני מכשירים יגלו את כל המכשירים הם יכולים ליצור חיבור דו-כיווני לרשת Wi-Fi Aware ללא נקודת גישה.

חיבור לרשתות Wi-Fi Aware תומך בתפוקה גבוהה יותר לאורך זמן במרחקים מאשר ב-Bluetooth בחיבורים. סוגי חיבורים אלה שימושיים עבור אפליקציות שמשתפים כמויות של נתונים בין משתמשים, לדוגמה, אפליקציות של שיתוף תמונות.

שיפורים ב-Android 13 (רמת API 33)

במכשירים עם Android בגרסה 13 (רמת API 33) ואילך עם תמיכה באפליקציות ללא התקנה במצב תקשורת, אפליקציות יכולות להשתמש PublishConfig.Builder.setInstantCommunicationModeEnabled() ו- SubscribeConfig.Builder.setInstantCommunicationModeEnabled() אמצעים להשגת להפעיל או להשבית את מצב התקשורת המיידית עבור בעל אתר או מנוי סשן הגילוי. מצב תקשורת מיידית מאיץ את חילופי ההודעות, גילוי שירות, וכל נתיב נתונים שהוגדר כחלק מבעל תוכן דיגיטלי או מנוי סשן הגילוי. כדי לקבוע אם המכשיר תומך בתקשורת מיידית משתמשים בשיטה isInstantCommunicationModeSupported().

שיפורים ב-Android 12 (רמת API 31)

מערכת Android 12 (רמת API 31) מוסיפה כמה שיפורים ל-Wi-Fi Aware:

  • במכשירים שמותקנת בהם גרסת Android 12 (API ברמה 31) ואילך, אפשר להשתמש onServiceLost() התראה חוזרת (callback) כשהאפליקציה איבדה שירות שהתגלה כתוצאה הפסקת השירות או יציאה מהטווח.
  • ההגדרה של נתיבי נתונים של Wi-Fi Aware פשוטה יותר. גרסאות קודמות השתמשה בהודעות 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 API, כפי שמוצג בהמשך:

    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.
  • יצירת סשן Wi-Fi Aware עם מרחב שמות ייחודי שפועל מאגר לכל סשנים של גילוי שנוצרו בו.

אם האפליקציה תצורף בהצלחה, המערכת תריץ את הקובץ התקשרות חזרה onAttached(). הקריאה החוזרת (callback) הזו מספקת אובייקט 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() סשנים מסוג Discovery משויכים להורה שלהם 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() קריאה חוזרת (callback) באפליקציה. מאחר שאפשר להשתמש ארגומנט SubscribeDiscoverySession ב קריאה חוזרת כדי לתקשר עם בעל אפליקציה אחרי שהאפליקציה גילתה את התג, יש לשמור את ההפניה. אפשר לעדכן את סשן ההרשמה בכל שלב עד שיחות updateSubscribe() בפעילות הגילוי.

בשלב הזה, המינוי שלכם ממתין לתוצאות של בעלי תוכן דיגיטלי תואמים טווח Wi-Fi. במקרה כזה, המערכת עורכת את onServiceDiscovered() שיטת קריאה חוזרת. אפשר להשתמש ב-PeerHandle מהקריאה החוזרת לארגומנט הזה כדי לשלוח הודעה או ליצור חיבור אל המו"ל.

כדי להפסיק את ההרשמה לשירות, צריך להתקשר DiscoverySession.close() סשנים מסוג Discovery משויכים להורה שלהם WifiAwareSession אם סשן ההורה הוא נסגרה, וסשנים של גילוי שמשויכים אליו סגורים גם הם. בזמן מחיקה גם האובייקטים סגורים, המערכת לא יכולה להבטיח שהם לא נמצאים בטווח הסשנים סגורים, לכן מומלץ לקרוא באופן מפורש ל-close() שיטות.

שליחת הודעה

כדי לשלוח הודעה למכשיר אחר, צריך את האובייקטים הבאים:

כדי לשלוח הודעה, צריך להתקשר sendMessage() לאחר מכן עשויות להתרחש הקריאות החוזרות הבאות:

  • כשההודעה מתקבלת בהצלחה על ידי האפליקציה להשוואה, המערכת קוראת ל- onMessageSendSucceeded() להתקשרות חזרה באפליקציה שליחה.
  • כשהעמית מקבל הודעה, המערכת קוראת ל- onMessageReceived() באפליקציה הקבלה.

PeerHandle נדרש כדי לתקשר עם אפליקציות להשוואה, אבל לא כדאי מסתמכים עליו כמזהה קבוע של אפליקציות להשוואה. מזהים ברמה גבוהה יותר יכולים להיות שבו האפליקציה משתמשת - מוטמעת בשירות הגילוי עצמו בהודעות הבאות. אפשר להטמיע מזהה בשירות הגילוי עם ה setMatchFilter() או setServiceSpecificInfo() שיטה של PublishConfig או SubscribeConfig. השיטה setMatchFilter() משפיעה על הגילוי, ואילו השיטה setServiceSpecificInfo() לא משפיעה על הגילוי.

הטמעת מזהה בהודעה מרמזת על שינוי מערך הבייטים של ההודעה לכלול מזהה (לדוגמה, כשני הבייטים הראשונים).

יצירת חיבור

Wi-Fi Aware תומך ברשת שרת לקוח בין שני מכשירי Wi-Fi Aware.

כדי להגדיר את החיבור לשרת-לקוח:

  1. להשתמש ב-Wi-Fi Aware Discovery כדי לפרסם שירות ( ולהירשם לשירות (ב לקוח).

  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 השיטות המתאימות של קריאה חוזרת (callback) מופעלות כאשר חיבור הרשת זמין, השתנה או אבד.

  7. לאחר קריאה לשיטה onAvailable() אצל המנוי, אובייקט Network זמין עם שאפשר לפתוח Socket כדי לתקשר עם ServerSocket באתר של בעל האתר, אבל עליך לדעת כתובת ה-IPv6 והיציאה של ServerSocket. אתם מקבלים את אובייקט NetworkCapabilities סופקו בקריאה החוזרת (callback) של 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 RTT יכולות למדוד ישירות את המרחק אל אפליקציות אחרות ולהשתמש במידע הזה כדי להגביל את גילוי שירות ה-Wi-Fi Aware.

ממשק ה-Wi-Fi RTT API מאפשר טווח ישיר לעמית עם Wi-Fi Aware באמצעות כתובת ה-MAC או ה-PeerHandle שלה.

ניתן להגביל את החשיפה ל-Wi-Fi Aware כך שיגלו שירותים רק במסגרת גבול וירטואלי מסוים. לדוגמה, אפשר להגדיר גבולות וירטואליים שמאפשרים גילוי של מכשיר שמפרסם שירות "Aware_File_Share_Service_Name" שלא קרוב ל-3 מטרים (מצוין כ-3,000 מ"מ) ולא יותר מ-10 מטרים (מצוין כ-10,000 מ"מ).

כדי להפעיל גבולות וירטואליים, בעל התוכן הדיגיטלי וגם המנוי צריכים לבצע את הפעולות הבאות:

  • בעל התוכן הדיגיטלי חייב להפעיל טווח בשירות שפורסם באמצעות setRangingEnabled(true).

    אם בעל התוכן הדיגיטלי לא מפעיל טווח, אזי מגבלות כלשהן שקשורות לגבולות וירטואליים שהמנוי התעלל מהן, ומתבצע גילוי רגיל, תוך התעלמות מהמרחק.

  • המנוי חייב לציין גבולות וירטואליים באמצעות שילוב כלשהו של setMinDestinationMm וגם setMaxMaxMm

    בכל אחד מהערכים האלה, מרחק שלא צוין לא מרמז על מגבלה. מציין רק המרחק המקסימלי מייצג מרחק מינימלי של 0. ציון של רק מרחק מינימלי לא מרמז על מספר מקסימלי.

כשמתגלה שירות אפליקציות להשוואה בתוך גבולות וירטואליים, onServiceDiscoveredWithinRange מופעלת קריאה חוזרת (callback), שמציינת את המרחק שנמדד מהעמית. לאחר מכן ניתן לקרוא לממשק ה-API של RTT ישיר ב-Wi-Fi לפי הצורך כדי למדוד את המרחק במועדים מאוחרים יותר.