教學課程:使用 Azure 通知中樞和 Google 雲端通訊 (已淘汰) 將通知推送至特定 Android 裝置Tutorial: Push notifications to specific Android devices using Azure Notification Hubs and Google Cloud Messaging (deprecated)

警告

Google 已於 2018 年 4 月 10 日淘汰 Google 雲端通訊 (GCM)。As of April 10, 2018, Google has deprecated Google Cloud Messaging (GCM). GCM 伺服器和用戶端 API 會由其他項目取代,並且很快就會在 2019 年 5 月 29 日進行移除。The GCM server and client APIs are deprecated and will be removed as soon as May 29, 2019. 如需詳細資訊,請參閱 GCM 和 FCM 常見問題集For more information, see GCM and FCM Frequently Asked Questions.

概觀Overview

本教學課程說明如何使用 Azure 通知中樞,將即時新聞通知廣播至 Android 應用程式。This tutorial shows you how to use Azure Notification Hubs to broadcast breaking news notifications to an Android app. 完成時,您便能夠註冊您所感興趣的即時新聞類別,並僅接收這些類別的推播通知。When complete, you will be able to register for breaking news categories you are interested in, and receive only push notifications for those categories. 此情況為適用於許多應用程式的常見模式,其中必須將通知傳送給先前宣告對該通知感興趣的使用者群組,例如 RSS 閱讀程式、供樂迷使用的應用程式等等。This scenario is a common pattern for many apps where notifications have to be sent to groups of users that have previously declared interest in them, for example, RSS reader, apps for music fans, etc.

在通知中樞內建立註冊時,您可以透過包含一或多個 tags 來啟用廣播案例。Broadcast scenarios are enabled by including one or more tags when creating a registration in the notification hub. 當標籤收到通知時,所有已註冊此標籤的裝置都會收到通知。When notifications are sent to a tag, all devices that have registered for the tag will receive the notification. 由於標籤只是簡單的字串而已,您無需預先佈建標籤。Because tags are simply strings, they do not have to be provisioned in advance. 如需標記的詳細資訊,請參閱通知中樞路由與標記運算式For more information about tags, see Notification Hubs Routing and Tag Expressions.

在本教學課程中,您會執行下列動作:In this tutorial, you do the following actions:

  • 在行動應用程式中新增類別選項。Add category selection to the mobile app.
  • 註冊附有標記的通知。Registered for notifications with tags.
  • 傳送加註標記的通知。Send tagged notifications.
  • 測試應用程式Test the app

必要條件Prerequisites

本教學課程以您在以下教學課程中建立的 Android 應用程式為基礎:教學課程:使用 Azure 通知中樞和 Google 雲端通訊將通知推送至 Android 裝置This tutorial builds on the app you created in Tutorial: Push notifications to Android devices by using Azure Notification Hubs and Google Cloud Messaging. 開始進行本教學課程之前,請完成教學課程:使用 Azure 通知中樞和 Google 雲端通訊將通知推送至 Android 裝置Before starting this tutorial, complete the Tutorial: Push notifications to Android devices by using Azure Notification Hubs and Google Cloud Messaging.

在應用程式中新增類別選項Add category selection to the app

第一個步驟是在您現有的主要活動上新增 UI 元素,以便使用者選取要註冊的類別。The first step is to add the UI elements to your existing main activity that enable the user to select categories to register. 使用者所選取的類別會儲存在裝置上。The categories selected by a user are stored on the device. 啟動應用程式時,您的通知中心內會建立以所選取類別作為標籤的裝置註冊。When the app starts, a device registration is created in your notification hub with the selected categories as tags.

  1. 開啟 res/layout/activity_main.xml file,然後以下列程式碼取代內容:Open the res/layout/activity_main.xml file, and replace the content with the following:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.breakingnews.MainActivity"
        android:orientation="vertical">
    
            <CheckBox
                android:id="@+id/worldBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/label_world" />
            <CheckBox
                android:id="@+id/politicsBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/label_politics" />
            <CheckBox
                android:id="@+id/businessBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/label_business" />
            <CheckBox
                android:id="@+id/technologyBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/label_technology" />
            <CheckBox
                android:id="@+id/scienceBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/label_science" />
            <CheckBox
                android:id="@+id/sportsBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/label_sports" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="subscribe"
                android:text="@string/button_subscribe" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:id="@+id/text_hello"
            />
    </LinearLayout>
    
  2. 開啟 res/values/strings.xml 檔案並新增下列幾行:Open the res/values/strings.xml file and add the following lines:

    <string name="button_subscribe">Subscribe</string>
    <string name="label_world">World</string>
    <string name="label_politics">Politics</string>
    <string name="label_business">Business</string>
    <string name="label_technology">Technology</string>
    <string name="label_science">Science</string>
    <string name="label_sports">Sports</string>
    

    您的 main_activity.xml 圖形版面配置應如下圖所示:Your main_activity.xml graphical layout should look like in the following image:

  3. 在與 MainActivity 類別相同的套件中建立 Notifications 類別。Create a class Notifications in the same package as your MainActivity class.

    import java.util.HashSet;
    import java.util.Set;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.os.AsyncTask;
    import android.util.Log;
    import android.widget.Toast;
    import android.view.View;
    
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    import com.microsoft.windowsazure.messaging.NotificationHub;
    
    public class Notifications {
        private static final String PREFS_NAME = "BreakingNewsCategories";
        private GoogleCloudMessaging gcm;
        private NotificationHub hub;
        private Context context;
        private String senderId;
    
        public Notifications(Context context, String senderId, String hubName,
                                String listenConnectionString) {
            this.context = context;
            this.senderId = senderId;
    
            gcm = GoogleCloudMessaging.getInstance(context);
            hub = new NotificationHub(hubName, listenConnectionString, context);
        }
    
        public void storeCategoriesAndSubscribe(Set<String> categories)
        {
            SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, 0);
            settings.edit().putStringSet("categories", categories).commit();
            subscribeToCategories(categories);
        }
    
        public Set<String> retrieveCategories() {
            SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, 0);
            return settings.getStringSet("categories", new HashSet<String>());
        }
    
        public void subscribeToCategories(final Set<String> categories) {
            new AsyncTask<Object, Object, Object>() {
                @Override
                protected Object doInBackground(Object... params) {
                    try {
                        String regid = gcm.register(senderId);
    
                        String templateBodyGCM = "{\"data\":{\"message\":\"$(messageParam)\"}}";
    
                        hub.registerTemplate(regid,"simpleGCMTemplate", templateBodyGCM,
                            categories.toArray(new String[categories.size()]));
                    } catch (Exception e) {
                        Log.e("MainActivity", "Failed to register - " + e.getMessage());
                        return e;
                    }
                    return null;
                }
    
                protected void onPostExecute(Object result) {
                    String message = "Subscribed for categories: "
                            + categories.toString();
                    Toast.makeText(context, message,
                            Toast.LENGTH_LONG).show();
                }
            }.execute(null, null, null);
        }
    
    }
    

    本類別會使用本機儲存體來儲存此裝置必須接收的新聞類別。This class uses the local storage to store the categories of news that this device has to receive. 它也包含註冊這些類別的方法。It also contains methods to register for these categories.

  4. MainActivity 類別中移除 NotificationHubGoogleCloudMessaging 的私人欄位,並新增 Notifications 的欄位:In your MainActivity class remove your private fields for NotificationHub and GoogleCloudMessaging, and add a field for Notifications:

    // private GoogleCloudMessaging gcm;
    // private NotificationHub hub;
    private Notifications notifications;
    
  5. 然後,在 onCreate 方法中,移除 hub 欄位和 registerWithNotificationHubs 方法的初始化。Then, in the onCreate method, remove the initialization of the hub field and the registerWithNotificationHubs method. 接著新增以下幾行,以初始化 Notifications 類別的執行個體。Then add the following lines, which initialize an instance of the Notifications class.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mainActivity = this;
    
        NotificationsManager.handleNotifications(this, NotificationSettings.SenderId,
                MyHandler.class);
    
        notifications = new Notifications(this, NotificationSettings.SenderId, NotificationSettings.HubName, NotificationSettings.HubListenConnectionString);
    
        notifications.subscribeToCategories(notifications.retrieveCategories());
    }
    

    確認中樞名稱和連接字串已正確設定於 NotificationSettings 類別中。Confirm that the hub name and the connection string are set properly in the NotificationSettings class.

    注意

    因為隨用戶端應用程式散佈的憑證通常不安全,您應只將接聽存取權的金鑰隨用戶端應用程式散佈。Because credentials that are distributed with a client app are not generally secure, you should only distribute the key for listen access with your client app. 您的應用程式可透過接聽存取權來註冊通知,但無法修改現有的註冊或無法傳送通知。Listen access enables your app to register for notifications, but existing registrations cannot be modified and notifications cannot be sent. 在安全的後端服務中,會使用完整存取金鑰來傳送通知和變更現有的註冊。The full access key is used in a secured backend service for sending notifications and changing existing registrations.

  6. 然後,新增下列匯入:Then, add the following imports:

    import android.widget.CheckBox;
    import java.util.HashSet;
    import java.util.Set;
    
  7. 新增下列 subscribe 方法,以處理 [訂閱] 按鈕的 click 事件:Add the following subscribe method to handle the subscribe button click event:

    public void subscribe(View sender) {
        final Set<String> categories = new HashSet<String>();
    
        CheckBox world = (CheckBox) findViewById(R.id.worldBox);
        if (world.isChecked())
            categories.add("world");
        CheckBox politics = (CheckBox) findViewById(R.id.politicsBox);
        if (politics.isChecked())
            categories.add("politics");
        CheckBox business = (CheckBox) findViewById(R.id.businessBox);
        if (business.isChecked())
            categories.add("business");
        CheckBox technology = (CheckBox) findViewById(R.id.technologyBox);
        if (technology.isChecked())
            categories.add("technology");
        CheckBox science = (CheckBox) findViewById(R.id.scienceBox);
        if (science.isChecked())
            categories.add("science");
        CheckBox sports = (CheckBox) findViewById(R.id.sportsBox);
        if (sports.isChecked())
            categories.add("sports");
    
        notifications.storeCategoriesAndSubscribe(categories);
    }
    

    此方法會建立一份類別清單,並使用 Notifications 類別在本機儲存體中儲存清單,並在通知中心註冊對應標籤。This method creates a list of categories and uses the Notifications class to store the list in the local storage and register the corresponding tags with your notification hub. 變更類別時,系統會使用新類別重新建立註冊。When categories are changed, the registration is recreated with the new categories.

您的應用程式現在可以在裝置上的本機儲存體中儲存一組類別,並在使用者每次變更類別選項時在通知中心註冊。Your app is now able to store a set of categories in local storage on the device and register with the notification hub whenever the user changes the selection of categories.

註冊通知Register for notifications

這些步驟會在啟動時,使用已儲存在本機儲存體中的類別在通知中心註冊。These steps register with the notification hub on startup using the categories that have been stored in local storage.

注意

由於 Google 雲端通訊 (GCM) 所指派的 registrationId 可以隨時變更,您應經常註冊通知以避免通知失敗。Because the registrationId assigned by Google Cloud Messaging (GCM) can change at any time, you should register for notifications frequently to avoid notification failures. 此範例會在應用程式每次啟動時註冊通知。This example registers for notification every time that the app starts. 若是經常執行 (一天多次) 的應用程式,如果距離上次註冊的時間不到一天,則您可能可以略過註冊以保留頻寬。For apps that are run frequently, more than once a day, you can probably skip registration to preserve bandwidth if less than a day has passed since the previous registration.

  1. MainActivity 類別中 onCreate 方法的結尾新增下列程式碼:Add the following code at the end of the onCreate method in the MainActivity class:

    notifications.subscribeToCategories(notifications.retrieveCategories());
    

    此程式碼可確保應用程式每次啟動時都會從本機儲存體擷取類別,並要求這些類別的註冊。This code makes sure that every time the app starts it retrieves the categories from local storage and requests a registration for these categories.

  2. 然後如下所示,更新 MainActivity 類別的 onStart() 方法:Then update the onStart() method of the MainActivity class as follows:

    @Override
    protected void onStart() {
    
        super.onStart();
        isVisible = true;
    
        Set<String> categories = notifications.retrieveCategories();
    
        CheckBox world = (CheckBox) findViewById(R.id.worldBox);
        world.setChecked(categories.contains("world"));
        CheckBox politics = (CheckBox) findViewById(R.id.politicsBox);
        politics.setChecked(categories.contains("politics"));
        CheckBox business = (CheckBox) findViewById(R.id.businessBox);
        business.setChecked(categories.contains("business"));
        CheckBox technology = (CheckBox) findViewById(R.id.technologyBox);
        technology.setChecked(categories.contains("technology"));
        CheckBox science = (CheckBox) findViewById(R.id.scienceBox);
        science.setChecked(categories.contains("science"));
        CheckBox sports = (CheckBox) findViewById(R.id.sportsBox);
        sports.setChecked(categories.contains("sports"));
    }
    

    此程式碼會根據原先儲存的類別狀態更新主要活動。This code updates the main activity based on the status of previously saved categories.

現在已完成此應用程式,且可在裝置本機儲存體中儲存一組類別,以供每次使用者變更類別選項在通知中心註冊時使用。The app is now complete and can store a set of categories in the device local storage used to register with the notification hub whenever the user changes the selection of categories. 接著,定義可將類別通知傳送至此應用程式的後端。Next, define a backend that can send category notifications to this app.

傳送加註標記的通知Send tagged notifications

在本節中,您會從 .NET 主控台應用程式將即時新聞以加註標記的範本通知形式傳送。In this section, you send breaking news as tagged template notifications from a .NET console app.

  1. 在 Visual Studio 中,建立新的 Visual C# 主控台應用程式:In Visual Studio, create a new Visual C# console application:

    1. 在主功能表上,選取 [檔案] > [新增] > [專案] 。On the menu, select File > New > Project.
    2. 在 [建立新專案] 中,針對 C# 在範本清單中選取 [主控台應用程式 (.NET Framework)] ,接著選取 [下一步] 。In Create a new project, select Console App (.NET Framework) for C# in the list of templates, and select Next.
    3. 輸入應用程式的名稱。Enter a name for the app.
    4. 在 [解決方案] 中,選擇 [新增到解決方案] ,再選取 [建立] 以建立專案。For Solution, choose Add to solution, and select Create to create the project.
  2. 選取 [工具] > [NuGet 套件管理員] > [套件管理員主控台] ,然後在主控台視窗中執行下列命令:Select Tools > NuGet Package Manager > Package Manager Console and then, in the console window, run the following command:

    Install-Package Microsoft.Azure.NotificationHubs
    

    此動作會使用 Microsoft.Azure.NotificationHubs 套件來新增對 Azure 通知中樞 SDK 的參考。This action adds a reference to the Azure Notification Hubs SDK by using the Microsoft.Azure.NotificationHubs package.

  3. 開啟 Program.cs 檔案,並新增下列 using 陳述式:Open the Program.cs file, and add the following using statement:

    using Microsoft.Azure.NotificationHubs;
    
  4. Program 類別中,新增或取代 (如果方法已存在) 下列方法:In the Program class, add the following method, or replace it if it already exists:

    private static async void SendTemplateNotificationAsync()
    {
        // Define the notification hub.
        NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<connection string with full access>", "<hub name>");
    
        // Create an array of breaking news categories.
        var categories = new string[] { "World", "Politics", "Business", "Technology", "Science", "Sports"};
    
        // Send the notification as a template notification. All template registrations that contain
        // "messageParam" and the proper tags will receive the notifications.
        // This includes APNS, GCM, WNS, and MPNS template registrations.
    
        Dictionary<string, string> templateParams = new Dictionary<string, string>();
    
        foreach (var category in categories)
        {
            templateParams["messageParam"] = "Breaking " + category + " News!";
            await hub.SendTemplateNotificationAsync(templateParams, category);
        }
    }
    

    此程式碼會分別將範本通知傳送給字串陣列中的六個標籤。This code sends a template notification for each of the six tags in the string array. 使用標籤可確保裝置只會收到已登錄類別的通知。The use of tags ensures that devices receive notifications only for the registered categories.

  5. 在上述程式碼中,請使用您的通知中樞名稱及通知中樞儀表板的 DefaultFullSharedAccessSignature 連接字串,來取代 <hub name><connection string with full access> 預留位置。In the preceding code, replace the <hub name> and <connection string with full access> placeholders with your notification hub name and the connection string for DefaultFullSharedAccessSignature from the dashboard of your notification hub.

  6. Main() 方法中新增下列程式碼行:In the Main() method, add the following lines:

     SendTemplateNotificationAsync();
     Console.ReadLine();
    
  7. 建置主控台應用程式。Build the console app.

測試應用程式Test the app

  1. 使用 Android Studio,在您的 Android 裝置或模擬器上執行應用程式。In Android Studio, run the app on your Android device or emulator. 應用程式 UI 提供一組切換,可讓您選擇要訂閱的類別。The app UI provides a set of toggles that lets you choose the categories to subscribe to.

  2. 啟用一或多個類別切換,然後按一下 [訂閱] 。Enable one or more categories toggles, then click Subscribe. 應用程式會將選取的類別轉換成標籤,並在通知中心內為選取的標籤要求新裝置註冊。The app converts the selected categories into tags and requests a new device registration for the selected tags from the notification hub. 隨即會傳回已註冊的類別,且會顯示在快顯通知中。The registered categories are returned and displayed in a toast notification.

    訂閱類別

  3. 執行 .NET 主控台應用程式,這會傳送每個類別的通知。Run the .NET console app, which sends notifications for each category. 選取的類別通知會以快顯通知方式出現。Notifications for the selected categories appear as toast notifications.

    技術新聞通知

後續步驟Next steps

在本教學課程中,您已將廣播通知傳送至已註冊相關類別的特定 Android 裝置。In this tutorial, you sent broadcast notifications to specific Android devices that have registered for the categories. 若想了解如何將通知推送給特定使用者,請繼續進行下列教學課程:To learn how to push notifications to specific users, advance to the following tutorial: