这一篇要讨论如何使用Xamarin.Android整合GCM以及Windows Azure来实作Android手机上的推播通知服务。
这篇文章比较着重概念的部分,在开始读这篇之前,也可以先参考一下Xamarin网站上的文章原文来了解Android GCM的运作逻辑:
RemoteNotifications:An Overview of Remote Notifications inXamarin.Android
http://docs.xamarin.com/guides/cross-platform/application_fundamentals/notifications/android/remote_notifications_in_android
1. GCM Overview
GCM(Google cloudmessaging )是Google提供的一个免费的 Service,这个Service功能是在handles,sending,routing,queuing从Service端要推播给你手机的讯息。
若你的手机要能接收从GCM传送的讯息,你的手机上必须要有安装Google ServiceFramework。Google Service Framework是在你的手机上有安装Google Play Application的时候会自动安装起来。在你的手机开机执行的时候,Google Service Framework会Run在背景执行程序中。然后在背景程序里面接听GCM传送过来的讯息。接着它会负责将讯息反串行化给注册在App中的Intents或是broadcast。
2. GCMRequirements
• 4kb message limit -你要推送的讯息大小不可以超过4kb。
• Android 2.2-你的Android devices必须run在Android 2.2(API level 8)以上的版本。
• Google Play Store – Android Devices必须有安装Google Play Store。如果你要在仿真器上测试GCM功能的话,仿真器上就需要有安装Google APIs。
• Google Account-如果你的Android Device目前run的版本低于4.0.4的话,你就需要申请一个Google Account。
3.Google CloudMessaging in Action
3.1 App向GCM注册流程
App在一开始行时,App必须先向GCM注册。注册完成,GCM会回传一个registration ID给App。
这个registrationID是你的App run在这个AndroidDevice的唯一识别。这个App会负责传送registrationID给Server Application。当ServerApplication收到了registration ID后,目前这个注册的流程才被视为完成。
*官方是说这个registration ID不是常常更改,所以你不需要在每次App被启用的时候都去Run这个注册过程。
如果GCM要改变registration ID,GCM会在发送个通知给Android Application。
3.1 ServerApplication 推播讯息给Android Device流程
在Server Application要发送一个推播通知到Client端的时候,Server Application会把Message送给GCM,GCM会负责传送这个讯息给Device。GCM允许Server Application一次指定1000个接受讯息者。
* 如果当Server尝试要推播信息给一个Device,而这个Device刚好是脱机的状态。(ex.关机中,收不到讯号)。
GCM会Queue着这个讯息,等到Device重新连上线时,GCM会再重新传送这个讯息。不过GCM只会传送近期的讯息,这个设计是为了避免一些过期的信息或是重复性的讯息。(ex.你的Server正在推播一些限时优惠,但是使用者可能是关机的状态,等使用者重新启动后,这个限时优惠有可能已经过期了,这时候就没有在推播的必要。)
*如果使用者从手机上移除这个Application。但是Server application与 GCM都还不知道这个Device上App已经被移除了。这个推播讯息会继续被传送到Device上。不过Google Services Framework会接收到Server Application推送过来的讯息,然后它会发现这个App已经在手机上被移除了。这时候这个Device会回送一个讯息给GCM,告知GCM这个registration ID已经无效了。
3.3 GCM尝试推播信息给一个已经移除APP的Android Device流程
当Server application尝试推播一个讯息给一个已经无效的registration ID,GCM会回传一个错误讯息"Device Not Registered"。接着Server application就可以负责在它储存registration ID的数据库列表中移除掉已经失效的registration ID。
4.Setting UpGoogle Cloud Messaging
要建立一个整合GCM功能的App,有底下三个主要步骤要执行:
1.建立一个Google API Project –必须建立一个Google API项目,然后启用CGM服务与建立所对应的API Key。
2.开发一个Android App –这边可以建立或者是维护一个Android App。
3.建立一个Server Application –这个Server Application是负责推送讯息给Device。这个Server Application可以是任何平台来假设,例如ASP.Net,PHP…。在这一次的范例我先用Windows Azure来担任Server Application。
所以在这个范例中主要的执行流程如下:
1. 前往Google APIs网站上启用 Google CloudMessage服务。
2. 建立API钥匙。
3. 在Windows Azure上建立Mobile Service。
4. 在Windows Azure上输入CGM的API Key。
5. 在Visual Studio 2012里面新建一个AndroidApplication项目。
6. 修改程序项目程序
4.1Creating aGoogle API Project
4.1.1在开始Google Cloud Message前,首先要在Google apis里面建立一个Project.
请连结底下的网址来登入Google apis:
(https://code.google.com/apis/console/)
4.1.2完成建立Google apis project之后,可以在网址列上看见你的Project ID。稍后会在建立Android App时用到这个Project ID。
4.1.3接着在Google apis网站上,点选左边的Services按钮。这时会看到中间的网页部分List出所有的Service服务。
4.1.4在下方找到Google Cloud Messaging for Android这个服务,然后把它开启。
4.1.5然后点选左边的API Access,这个步骤我们要建立一个API Key,这个Key是要给Server Application所使用的。
在这个页面中间下方,点选下方[Create Android key]。
4.1.6在弹出的Configure Server Key for Xamarin Evolve GCMExample对话筐中,在Accept requestsfrom these server IP adderss下方输入你的GCM允许从那些IP位置来的Server Application可以传送推播讯息。若你在这边没有输入特定的IP位置,那就代表默认你允许任何IP位置来的Server Application要求这个GCM执行推播讯息的动作。
4.1.7 建立完成可以看到一个Key for server apps,底下的API Key会是在你建立Server Application时所需要的必要项目。
4.2Create theAndroid Application
在建立Android App时,首先很重要的是要取得Google API Project ID,这是作为App中的Sender ID。
接下来会有三个主要的步骤要处理:
1.权限(Permissions):一个Android application必须要设定权限可以使用Internet以及从GCM接收讯息。
2.广播接受器(BroadcastReceiver):当GCM要推送一个讯息到Android Device,Device上的背景程序Google Service Framework会负责接收由GCM推送过来的讯息,接着Google Service Framework会把这个讯息在传送给App。
在这个App里面我们就要建立一个广播接受器(BroadcastReceiver),来接收一个由Google Service Framework送过来的讯息。
3.IntentService:当广播接受器(BroadcastReceiver)并不会去对讯息做一些处理,如果要处理这些讯息,广播接受器会启动一个IntentService来处理接收到的讯息。
4.2.1. DeclarePermissions
l 在Android Application里面我们有几个权限必须要宣告,
l android.permission.INTERNET–要与GCM互动,必须允许APP有连接网络的权限。
l android.permission.WAKE_LOCK – 这是要防止在处理关于推播通知时,处理器不会进入睡眠状态。
l com.google.android.c2dm.permission.RECEIVE-这是让App有权限去向GCM注册以及接收GCM要推播的讯息。
l <package_name>.permission.C2D_MESSAGE -这个权限有两个目的,告知我们的Device这个APP可以去接收所有C2D_Messages。也告知Device没有其他的Application可以接收这些讯息。
// This will prevent other apps on the device from receiving GCM messages for this app // It is crucial that the package name does not start with an uppercase letter - this is forbidden by Android. [assembly: Permission(Name ="xamarin.sample.com.permission.C2D_MESSAGE")] [assembly: UsesPermission(Name ="xamarin.sample.com.permission.C2D_MESSAGE")] // Gives the app permission to register and receive messages [assembly: UsesPermission(Name ="com.google.android.c2dm.permission.RECEIVE")] // This permission is necessary only for Android 4.0.3 and below. [assembly: UsesPermission(Name ="android.permission.GET_ACCOUNTS")] // Need to access the internet for GCM [assembly: UsesPermission(Name ="android.permission.INTERNET")] // Needed to keep the processor from sleeping when a message arrives [assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
4.2.2. Creatinga Broadcast Receiver
接下来建立一个BroadcastReceiver类别,这个会接听以下从GCM回传的Intent:
com.google.android.c2dm.intent.RECEIVE–这是接收GCM推播的讯息。
com.google.android.c2dm.intent.REGISTRATION–这是接收前往GCM注册相关的讯息。
com.google.android.gcm.intent.RETRY–这是接收重新尝试前往GCM注册的讯息。
下方是建立BroadcastReceiver类别的范例程序:
[BroadcastReceiver(Permission= "com.google.android.c2dm.permission.SEND")] [IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" }, Categories = new string[] {"@PACKAGE_NAME@" })] [IntentFilter(new string[] { "com.google.android.c2dm.intent.REGISTRATION" }, Categories = new string[] {"@PACKAGE_NAME@" })] [IntentFilter(new string[] { "com.google.android.gcm.intent.RETRY" }, Categories = new string[] { "@PACKAGE_NAME@"})] public class MyGCMBroadcastReceiver : BroadcastReceiver { const string TAG = "PushHandlerBroadcastReceiver"; public override void OnReceive(Context context, Intent intent) { MyIntentService.RunIntentInService(context, intent); SetResult(Result.Ok, null, null); } }
4.2.3. 在AndroidManifest.xml里面新增底下的权限 to supportthe receiver:
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED" />
4.2.4. Creatingthe IntentService
BroadcastReceiver里面不应该包括着处理通知讯息的逻辑,所以我们这边要在撰写一个IntentService类别,让这个Serveice来负责处理当收到讯息时要和用户进行的互动。
*在上一个小节,在BroadcastReceiver的OnReceive事件里面呼叫了MyIntentService.RunIntentInService(context, intent);
这个方法。可以看到这个方法是被宣告在MyIntenService类别里面的一个静态方法。而在下方Service类别中,里面有一段intent.Action;宣告,表示你可以经由这个宣告来判定目前所接收到的讯息到底是由App向GCM注册后得到回传的讯息还是由GCM发起推播,Device接收到讯息?
[Service] public class MyIntentService : IntentService { static PowerManager.WakeLock sWakeLock; static object LOCK = new object(); static void RunIntentInService(Context context, Intent intent) { lock (LOCK) { if (sWakeLock == null) { // This is called from BroadcastReceiver, there is no init. var pm = PowerManager.FromContext(context); WakeLock = pm.NewWakeLock( WakeLockFlags.Partial, "My WakeLock Tag"); } } sWakeLock.Acquire(); intent.SetClass(context, typeof(MyIntentService)); context.StartService(intent); } protected override void OnHandleIntent(Intent intent) { try { Context context = this.ApplicationContext; string action = intent.Action; if (action.Equals("com.google.android.c2dm.intent.REGISTRATION")) { HandleRegistration(context, intent); } else if (action.Equals("com.google.android.c2dm.intent.RECEIVE")) { HandleMessage(context, intent); } } finally { lock (LOCK) { //Sanity check for null as this is a public method if (sWakeLock != null) sWakeLock.Release(); } } } }
4.2.5.Registering with Google Cloud Messaging
接下来就是了解Android App如何去向GCM做注册的动作。在Android Application要去向GCM注册前,首先Android App会传送一个com.google.android.c2dm.intent.REGISTERIntent给GCM。
这个Intent会需要两个参数值:
app – 这是一个允许Google Services Framework去向Application取得向GCM注册必要信息的PendingIntent。
Sender- 这是一个用逗号分隔字符串数组,里面包含着要推播信息给这个App的Sender IDs。
请参考下方的Sample code。
string senders = "<google cloud="" messaging="" sender="">"; Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER"); intent.SetPackage("com.google.android.gsf"); intent.PutExtra("app", PendingIntent.GetBroadcast(context, 0, new Intent(), 0)); intent.PutExtra("sender", senders); context.StartService(intent);</google>
4.3 Roles of theApplication Serv
在这一篇我们是用Window Azure来当作我们的ServerApplication。在Windows Azure上要执行的步骤有底下几个:
1. 建立一个Mobile Service
在Windows Azure网站上按[New]的项目,然后选择建立Mobile Service。
这边需要自定一个Mobile Service URL名称。到这个步骤WindowsAzure Mobile Service就建立完成。
2. 建立一个todoitem数据库
点选到刚刚建立的Mobile Service,展开画面中间下方的[CREATE A NEWANDROID APP],在中间找到[Create a table]。这边Windows Azure会帮我们在Windows Azure上面建立一个[Todoitem]数据库。
3. 新增你的API Key到Windows Azure
点选Windows Azure上方的PUSH项目,找到[Google Cloud messaging settings],把在Google apis里面建立的API Key贴过来。在Windows Azure的设定到目前为止就完成了。
4. 新增Server site的Script
function insert(item, user, request) { request.execute({ success: function() { // Write to the response and then send the notification in the background request.respond(); push.gcm.send(item.channel, item.text, { success: function(response) { console.log('Push notification sent: ', response); }, error: function(error) { console.log('Error sending push notification: ', error); } }); } }) }
4.4 测试Android App
要能在仿真器上测试GCM,你的仿真器必须要有支持with Google Apps的仿真器。
范例程序可从Xamarin的网站下载。
http://components.xamarin.com/view/azure-mobile-services/
这个范例需要根据Windows Azure的数据库结构做一些微调,在我的测试中,我在Android应用程序中新增了文字之后,按下Add Item的按钮。
可以看到Android手机的左上角出现了一个小icon。
下拉这一个icon,可以看到GCM送来的通知项目。
这时我们回到Windows Azure的数据库上去查询刚刚被我们写入的资料,可以看到多了一笔我们刚刚新增的资料。
在这边有两个部分比较重要,第三个complete字段里面是一个false值,这个字段是用来判断使用者到底读取了这则讯息没有。
第四个channel字段里面记载的就是AndroidDevice向GCM注册后,GCM回传的registrationID。
回到Android Device点选到刚刚推播过来的讯息,这时信息已经被读取。接着再回到Windows Azure查询数据库,可以看见complete字段的属性被改成true。
参考文献
RemoteNotifications
http://docs.xamarin.com/guides/cross-platform/application_fundamentals/notifications/android/remote_notifications_in_android
Get started withpush notifications in Mobile Services
http://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-with-push-android/
转载自:昕力大学