XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2016/07/20

Xamarin.Forms Azure 行動推播中樞

Azure 行動推播中樞

想要能夠讓您開發的 Xamarin.Forms 應用程式,接收到來自遠端的訊息推播,這需要您:
  • 申請與啟用 Google Cloud Messaging (GCM) (對於 Google 平台行動裝置而言) / Apple Push Notification Service (APNS) (對於 iOS 行動平台裝置而言) / Windows Push Notification Services (WNS) (對於 Windows 行動平台裝置而言)
  • 申請與建立 Azure 行動應用的推播設定
  • 修改 Azure 行動應用的後端
  • 修改 Xamarin.Forms 應用程式
在這裡,將以 Android 平台作為實作說明,首先,需要申請 oogle Cloud Messaging (GCM), 接著,嘗試修正 附件 Azure Mobile App 後端服務建立說明 文章中的 Azure Mobile App 後端服務專案 與 Azure Mobile App 前端專案 程式碼。

申請 Google Cloud Messaging (GCM)

  1. 首先,打開網頁,進入到 Google Cloud Console https://console.developers.google.com/iam-admin/projects
  2. 點選 + 建立專案 連結
  3. 當 建立專案 對話窗出現之後,請在 專案名稱 欄位內填入 DoggyMobileGCM,您可以看到您的專案 ID 顯示在對話窗內,而後點選 建立 按鈕
    GCM建立專案
  4. 當專案建立完成之後並且出現在所有專案清單內,請點選這個剛剛產生的專案 DoggyMobileGCM
    GCM專案建立完成
  5. 當 IAM與管理員 頁面出現後,點選 設定,您會看到 專案編號 欄位,請將此編號 (213736323010) 複製下來,等下會用到
    GCM專案編號
  6. 接著,請點畫面中右上方的 Google APIs 圖示連結,進入到 Google APIs 申請頁面,當然,也可以直接輸入這個網址 : https://console.developers.google.com/apis/library?project=doggymobilegcm
    GCMGoogleAPIs圖示
  7. 進入到 API管理員 頁面,請找到 行動服務類 API 標題,接著點選 Google Cloud Messaging
    GCMAPI管理員
  8. 總覽頁面看到之後,請點選 啟用 按鈕,當啟用完成之後,接著點選左方的 憑證 進入到憑證設定頁面
    GCM總覽
    下圖圍啟用完成
    GCMAPI啟用完成
  9. 此時,網頁中間會出現 API 憑證 這個對話窗 ,請點選 建立憑證 按鈕,接著點選 API金鑰 選項。
    GCMAPI憑證
  10. 而後,會出現 建立新的金鑰 對話窗,請點選 「伺服器」金鑰 按鈕
    GCM建立新的金鑰
  11. 當回到 憑證 頁面,如下圖,請在 名稱 欄位內輸入 伺服器金鑰DoggyMobile 做為日後識別之用,接著點選 建立 按鈕。
    GCM建立伺服器API金鑰
  12. 最後,您會看到您申請的 API 金鑰 已經產生出來了 AIzaSyCp2pENhEkrSD1tErz1AQyb2FN8zuz7TpQ 請複製這個金鑰,等下會用到。您可以點選 確定 按鈕,以關閉這個對話窗。
    GCMAPI金鑰產生完成
    GCM憑證產生結果清單

Azure 行動應用之推送設定

  1. 請回到 Azure 儀表板,接著點選 doggymobilebe 行動 App 圖示,進入到 doggymobilebe 行動 App 設定刀鋒頁面。
  2. 在 設定 刀鋒頁面,點選 推送
  3. 在 Create Notificati... 刀鋒頁面,點選 Notification Hub
  4. 在 Notification Hub 刀鋒頁面,點選 + Notification Hub
    NotiHub建立1
  5. 在剛剛出現新的 Notification Hub 刀鋒頁面
    • 請在 Notification Hub 欄位內,輸入 DoggyMobileNotificationHub
    • 請點選 Namespace 設定必要設定 下面一點點的 Or create new 這個連結。(在此假設您需要為這個 Notification Hub產生一個新的Namespace`, 若您的 Azure 上已經有新的 Namespace,可以直接選取)。
    • 請在 Create a new namespace 欄位內,輸入 DoggyMobileNotiHubNamespace
    • 請選擇 釘選到儀表板 檢查盒,使其在勾選狀態下
    • 最後請點選 確定 按鈕
    NotiHub建立2
  6. 此時,多餘的刀鋒視窗會自動關閉,剩下 Create Notificati... 刀鋒視窗,請在該刀鋒視窗下方,點選 建立 按鈕
  7. 此時會回到 Azure 儀表板,當剛剛建立的 Notification Hub & Namespace 建立完成之後(您也可以從右上方的提示圖示中看到處理進度與是否完成),點選 doggymobilebe 行動 App 圖示,進入到doggymobilebe 行動 App 設定刀鋒頁面。
  8. 此時在 設定 刀鋒頁面內,您會看到一個 推送 (DoggyMobileNotificationHu... 項目,請點選這個項目
  9. 在 Push notification... 刀鋒頁面,點選 Google (GCM)
  10. 在 Google (GC...) 刀鋒頁面,請在 API Key 欄位中,輸入剛剛在 Google Cloud Messaging (GCM) 內申請得到的 API Key (AIzaSyCp2pENhEkrSD1tErz1AQyb2FN8zuz7TpQ),而後,點選 Save 按鈕。
    當儲存成功的訊息 (Success Notification Hub updated successfully!) 顯示在螢幕上,請點選 確定 按鈕
    GCM綁定AzureMobileApp
    GCM綁定AzureMobileApp完成通知

修改 Azure 行動應用的後端

  1. 請根據 Azure Mobile App 後端服務建立說明 文章中,最後下載的 Azure Mobile App 後端服務專案, 使用 Visual Studio 2015,開啟 Azure Mobile App 前端專案 DoggyMobileBE.sln
  2. 請先安裝這個 Microsoft.Azure.NotificationHubs NuGet 套件到專案內。
  3. 在方案總管內,展開專案 DoggyMobileBEService > Controllers,接著打開 TodoItemController.cs檔案。
    • 將底下 using 程式碼加入到這個檔案內
using System.Collections.Generic;
using Microsoft.Azure.NotificationHubs;
using Microsoft.Azure.Mobile.Server.Config;
  • 在 PostTodoItem 方法內,請將底下程式碼加入到呼叫 InsertAsync 方法之後
// Get the settings for the server project.
HttpConfiguration config = this.Configuration;
MobileAppSettingsDictionary settings = 
    this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();

// Get the Notification Hubs credentials for the Mobile App.
string notificationHubName = settings.NotificationHubName;
string notificationHubConnection = settings
    .Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString;

// Create a new Notification Hub client.
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString(notificationHubConnection, notificationHubName);

// Sending the message so that all template registrations that contain "messageParam"
// will receive the notifications. This includes APNS, GCM, WNS, and MPNS template registrations.
Dictionary<string,string> templateParams = new Dictionary<string,string>();
templateParams["messageParam"] = item.Text + " was added to the list.";

try
{
    // Send the push notification and log the results.
    var result = await hub.SendTemplateNotificationAsync(templateParams);

    // Write the success result to the logs.
    config.Services.GetTraceWriter().Info(result.State.ToString());
}
catch (System.Exception ex)
{
    // Write the failure result to the logs.
    config.Services.GetTraceWriter()
        .Error(ex.Message, null, "Push.SendAsync Error");
}
  1. 請重新 發行 這個專案

修改 DoggyMobileBE.Droid 專案

  1. 請根據 Azure Mobile App 後端服務建立說明 文章中,最後下載的 Azure Mobile App 前端專案, 使用 Visual Studio 2015,開啟 Azure Mobile App 前端專案 DoggyMobileBE.sln
  2. 請展開專案 DoggyMobileBE.Droid,使用滑鼠右擊 Components 節點,選擇 Get More Components...
    • 在 All Components 對話窗內,請搜尋 Google Cloud Messaging Client 這個元件,找到後,點選這個找到項目
      AndroidComponents
    • 當出現 Xamarin Component Store ▶ Google Cloud Messaging Client 對話窗時候,請點選右方的Add to App 按鈕
      AndroidComponents1
  3. 打開 MainActivity.cs 檔案
    • 加入底下 using 敘述到這個檔案內
using Gcm.Client;
  • 在 OnCreate 方法內,在 LoadApplication 之後,加入底下程式碼
try
{
    // Check to ensure everything's setup right
    GcmClient.CheckDevice(this);
    GcmClient.CheckManifest(this);

    // Register for push notifications
    System.Diagnostics.Debug.WriteLine("Registering...");
    GcmClient.Register(this, PushHandlerBroadcastReceiver.SENDER_IDS);
}
catch (Java.Net.MalformedURLException)
{
    CreateAndShowDialog("There was an error creating the client. Verify the URL.", "Error");
}
catch (Exception e)
{
    CreateAndShowDialog(e.Message, "Error");
}
  • 將底下程式碼的 CreateAndShowDialog 輔助方法加入到這個檔案 MainActivity 類別
private void CreateAndShowDialog(String message, String title)
{
    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    builder.SetMessage (message);
    builder.SetTitle (title);
    builder.Create().Show ();
}
  • 在 MainActivity 類別內,加入底下屬性宣告程式碼
// Create a new instance field for this activity.
static MainActivity instance = null;

// Return the current activity instance.
public static MainActivity CurrentActivity
{
    get
    {
        return instance;
    }
}
  • 在 OnCreate 方法內的最前面,加入底下初始化 instance 的程式碼
// Set the current instance of MainActivity.
instance = this;
  1. 滑鼠右擊專案 DoggyMobileBE.Droid 節點,選擇 加入 > 類別
    • 請點選 Visual C# > Class
    • 在底下 名稱 欄位內輸入 GcmService
    • 點選 新增 按鈕
  2. 在 GcmService.cs 檔案內
    • 加入底下 using 敘述
using Android.App;
using Android.Content;
using Android.Media;
using Android.Support.V4.App;
using Android.Util;
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
  1. 在 using 敘述之後與 namespace 之前,加入底下程式碼
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
//GET_ACCOUNTS is only needed for android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
  1. 在 namespace 之後,加入底下新增的類別定義程式碼
    • 請將之前在 Google Cloud Messaging (GCM) 取得的 專案編號(也就是 213736323010 ) 替換掉底下文字 <PROJECT_NUMBER>
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "@PACKAGE_NAME@" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "@PACKAGE_NAME@" })]
public class PushHandlerBroadcastReceiver : GcmBroadcastReceiverBase<GcmService>
{
    public static string[] SENDER_IDS = new string[] { "213736323010" };
}
  1. 使用底下程式碼,將 GcmService 類別定義替換掉
 [Service]
 public class GcmService : GcmServiceBase
 {
     public static string RegistrationID { get; private set; }

     public GcmService()
         : base(PushHandlerBroadcastReceiver.SENDER_IDS){}
 }
  1. 使用底下程式碼,加入到 GcmService 類別內
    ```cs protected override void OnRegistered(Context context, string registrationId) { Log.Verbose("PushHandlerBroadcastReceiver", "GCM Registered: " + registrationId); RegistrationID = registrationId;
    var push = TodoItemManager.DefaultManager.CurrentClient.GetPush();
    MainActivity.CurrentActivity.RunOnUiThread(() => Register(push, null)); }
public async void Register(Microsoft.WindowsAzure.MobileServices.Push push, IEnumerable tags) { try { const string templateBodyGCM = "{\"data\":{\"message\":\"$(messageParam)\"}}";
    JObject templates = new JObject();
    templates["genericMessage"] = new JObject
    {
        {"body", templateBodyGCM}
    };

    await push.RegisterAsync(RegistrationID, templates);
    Log.Info("Push Installation Id", push.InstallationId.ToString());
}
catch (Exception ex)
{
    System.Diagnostics.Debug.WriteLine(ex.Message);
    Debugger.Break();
}
}

10.  使用底下程式碼,加入到 GcmService 類別內

```cs
protected override void OnMessage(Context context, Intent intent)
{
    Log.Info("PushHandlerBroadcastReceiver", "GCM Message Received!");

    var msg = new StringBuilder();

    if (intent != null && intent.Extras != null)
    {
        foreach (var key in intent.Extras.KeySet())
            msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());
    }

    //Store the message
    var prefs = GetSharedPreferences(context.PackageName, FileCreationMode.Private);
    var edit = prefs.Edit();
    edit.PutString("last_msg", msg.ToString());
    edit.Commit();

    string message = intent.Extras.GetString("message");
    if (!string.IsNullOrEmpty(message))
    {
        createNotification("New todo item!", "Todo item: " + message);
        return;
    }

    string msg2 = intent.Extras.GetString("msg");
    if (!string.IsNullOrEmpty(msg2))
    {
        createNotification("New hub message!", msg2);
        return;
    }

    createNotification("Unknown message details", msg.ToString());
}

void createNotification(string title, string desc)
{
    //Create notification
    var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;

    //Create an intent to show ui
    var uiIntent = new Intent(this, typeof(MainActivity));

    //Use Notification Builder
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

    //Create the notification
    //we use the pending intent, passing our ui intent over which will get called
    //when the notification is tapped.
    var notification = builder.SetContentIntent(PendingIntent.GetActivity(this, 0, uiIntent, 0))
            .SetSmallIcon(Android.Resource.Drawable.SymActionEmail)
            .SetTicker(title)
            .SetContentTitle(title)
            .SetContentText(desc)

            //Set the notification sound
            .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))

            //Auto cancel will remove the notification once the user touches it
            .SetAutoCancel(true).Build();

    //Show the notification
    notificationManager.Notify(1, notification);
}
  1. 使用底下程式碼,加入到 GcmService 類別內
protected override void OnUnRegistered(Context context, string registrationId)
{
    Log.Error("PushHandlerBroadcastReceiver", "Unregistered RegisterationId : " + registrationId);
}

protected override void OnError(Context context, string errorId)
{
    Log.Error("PushHandlerBroadcastReceiver", "GCM Error: " + errorId);
}
  1. 滑鼠右擊 DoggyMobileBE.Droid,選擇 選擇 設定為起始專案,並且按下 F5 開始執行
    Android推播執行結果1
    Android推播執行結果2
    Android推播執行結果3
    Android推播執行結果4

沒有留言:

張貼留言