Android 移动推送

Android 移动推送,android,amazon-web-services,xamarin,google-cloud-messaging,amazon-sns,Android,Amazon Web Services,Xamarin,Google Cloud Messaging,Amazon Sns,我目前正在Xamarin开发一个Android应用程序。我正在使用AWS SNS推送和谷歌云信使(GCM) 我一直在密切关注本演练: 我一直在使用的代码与那里的代码非常相似。但是,我有一个注册意向服务,其工作原理如下: [Service(Exported = false)] public class RegistrationIntentService : IntentService { private static object locker = new object();

我目前正在Xamarin开发一个Android应用程序。我正在使用AWS SNS推送和谷歌云信使(GCM)

我一直在密切关注本演练:

我一直在使用的代码与那里的代码非常相似。但是,我有一个注册意向服务,其工作原理如下:

  [Service(Exported = false)]
  public class RegistrationIntentService : IntentService
  {
    private static object locker = new object();

    public RegistrationIntentService() : base("RegistrationIntentService") { }

    protected override void OnHandleIntent(Intent intent)
    {
        try
        {
            Logging.LogMessage(Application, "RegistrationIntentService", "Calling InstanceID.GetToken", LogType.Debug);
            lock (locker)
            {
                var instanceID = InstanceID.GetInstance(Application.Context);
                Constants.token = instanceID.GetToken(
                    Constants.senderId, GoogleCloudMessaging.InstanceIdScope, null);

                Logging.LogMessage(Application, "RegistrationIntentService", "GCM Registration Token: " + Constants.token, LogType.Debug);
                /*SendRegistrationToAppServer(token).GetAwaiter().GetResult();

                Log.Info("RegistrationIntentService", "Registered");*/

                SendRegistrationToAppServer(Constants.token).GetAwaiter().GetResult();

                Logging.LogMessage(Application, "RegistrationIntentService", "Registered", LogType.Debug);

                Subscribe(Constants.token);
            } // Release lock

        }
        catch (Exception e)
        {
            Logging.LogMessage(Application, "RegistrationIntentService", "Failed to get a registration token. Exception:\n" + e.ToString(), LogType.Error);
        }
    }

    private async System.Threading.Tasks.Task SendRegistrationToAppServer(string token)
    {
        var config = new AmazonSimpleNotificationServiceConfig()
        {
            RegionEndpoint = RegionEndpoint.USEast1
        };

        var credentials = new BasicAWSCredentials(Constants.accessKeyId, Constants.secretAccessKey);

        Constants.client = new AmazonSimpleNotificationServiceClient(credentials, config);

        Logging.LogMessage(this, "RegistrationIntentService.SendRegistrationToAppServer", "Created client", LogType.Debug);

        if (Constants.createdEndpoint == null)
        {
            var endpoint = new CreatePlatformEndpointRequest()
            {
                PlatformApplicationArn = Constants.endPoint,
                Token = token
            };

            var endpointResponse = await Constants.client.CreatePlatformEndpointAsync(endpoint);
            Logging.LogMessage(this, "RegistrationIntentService.SendRegistrationToAppServer", "Got endpoint. ARN: " + endpointResponse.EndpointArn, LogType.Debug);
            Constants.createdEndpoint = endpointResponse.EndpointArn;
        }

        // Make sure we haven't subscribed yet
        if (Constants.createdEndpoint != null && Constants.subscriptionArn == null)
        {
            var subscription = await Constants.client.SubscribeAsync(Constants.topicARNBeginning + Constants.devicePhoneNumber, "Application", Constants.createdEndpoint);
            Logging.LogMessage(this, "RegistrationIntentService.SendRegistrationToAppServer", "AWS Subscribed", LogType.Debug);
        }
    }

    private bool Subscribe(string token)
    {
        var pubSub = GcmPubSub.GetInstance(Application.Context);
        const string topic = "/topics/global";

        try
        {
            pubSub.Subscribe(token, topic, null);
            Logging.LogMessage(this, "RegistrationIntentService.Subscribe", "GCM Subscribed", LogType.Debug);
            return true;
        }
        catch (Java.IO.IOException)
        {
            try
            {
                pubSub.Unsubscribe(token, topic);

                pubSub.Subscribe(token, topic, null);

                return true;
            }
            catch (Java.IO.IOException)
            {
                Logging.LogMessage(Application, "Subscribe", "Failed to register", LogType.Error);
                return false;
            }
        }
    }
}
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="com.gcmmessaging" />
        </intent-filter>
    </receiver>
我使用MainActivity OnCreate事件处理程序中的StartService()调用显式启动注册意图服务。我确保设置了文档中要求的所有权限:

[assembly: UsesPermission(Android.Manifest.Permission.ReceiveBootCompleted)]
[assembly: UsesPermission (Android.Manifest.Permission.Internet)]
[assembly: UsesPermission (Android.Manifest.Permission.WakeLock)]
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
[assembly: UsesPermission("com.google.android.c2dm.permission.RECEIVE")]
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE", ProtectionLevel = Protection.Signature)]
[assembly: UsesPermission("@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission("com.google.android.c2dm.permission.SEND")]
我通过AssemblyInfo.cs和适当的C#属性(例如[Service]属性)创建了大部分Android清单。我在XML中明确声明的唯一内容(应用程序除外)如下:

  [Service(Exported = false)]
  public class RegistrationIntentService : IntentService
  {
    private static object locker = new object();

    public RegistrationIntentService() : base("RegistrationIntentService") { }

    protected override void OnHandleIntent(Intent intent)
    {
        try
        {
            Logging.LogMessage(Application, "RegistrationIntentService", "Calling InstanceID.GetToken", LogType.Debug);
            lock (locker)
            {
                var instanceID = InstanceID.GetInstance(Application.Context);
                Constants.token = instanceID.GetToken(
                    Constants.senderId, GoogleCloudMessaging.InstanceIdScope, null);

                Logging.LogMessage(Application, "RegistrationIntentService", "GCM Registration Token: " + Constants.token, LogType.Debug);
                /*SendRegistrationToAppServer(token).GetAwaiter().GetResult();

                Log.Info("RegistrationIntentService", "Registered");*/

                SendRegistrationToAppServer(Constants.token).GetAwaiter().GetResult();

                Logging.LogMessage(Application, "RegistrationIntentService", "Registered", LogType.Debug);

                Subscribe(Constants.token);
            } // Release lock

        }
        catch (Exception e)
        {
            Logging.LogMessage(Application, "RegistrationIntentService", "Failed to get a registration token. Exception:\n" + e.ToString(), LogType.Error);
        }
    }

    private async System.Threading.Tasks.Task SendRegistrationToAppServer(string token)
    {
        var config = new AmazonSimpleNotificationServiceConfig()
        {
            RegionEndpoint = RegionEndpoint.USEast1
        };

        var credentials = new BasicAWSCredentials(Constants.accessKeyId, Constants.secretAccessKey);

        Constants.client = new AmazonSimpleNotificationServiceClient(credentials, config);

        Logging.LogMessage(this, "RegistrationIntentService.SendRegistrationToAppServer", "Created client", LogType.Debug);

        if (Constants.createdEndpoint == null)
        {
            var endpoint = new CreatePlatformEndpointRequest()
            {
                PlatformApplicationArn = Constants.endPoint,
                Token = token
            };

            var endpointResponse = await Constants.client.CreatePlatformEndpointAsync(endpoint);
            Logging.LogMessage(this, "RegistrationIntentService.SendRegistrationToAppServer", "Got endpoint. ARN: " + endpointResponse.EndpointArn, LogType.Debug);
            Constants.createdEndpoint = endpointResponse.EndpointArn;
        }

        // Make sure we haven't subscribed yet
        if (Constants.createdEndpoint != null && Constants.subscriptionArn == null)
        {
            var subscription = await Constants.client.SubscribeAsync(Constants.topicARNBeginning + Constants.devicePhoneNumber, "Application", Constants.createdEndpoint);
            Logging.LogMessage(this, "RegistrationIntentService.SendRegistrationToAppServer", "AWS Subscribed", LogType.Debug);
        }
    }

    private bool Subscribe(string token)
    {
        var pubSub = GcmPubSub.GetInstance(Application.Context);
        const string topic = "/topics/global";

        try
        {
            pubSub.Subscribe(token, topic, null);
            Logging.LogMessage(this, "RegistrationIntentService.Subscribe", "GCM Subscribed", LogType.Debug);
            return true;
        }
        catch (Java.IO.IOException)
        {
            try
            {
                pubSub.Unsubscribe(token, topic);

                pubSub.Subscribe(token, topic, null);

                return true;
            }
            catch (Java.IO.IOException)
            {
                Logging.LogMessage(Application, "Subscribe", "Failed to register", LogType.Error);
                return false;
            }
        }
    }
}
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="com.gcmmessaging" />
        </intent-filter>
    </receiver>
我目前收到一个GCM令牌,并正确订阅了GCM和SNS。我仔细检查了返回码,我肯定得到了一个看起来有效的GCM令牌,我的订阅显示在SNS中。我订阅GCM的调用成功,没有抛出任何异常。然而,我实际上没有收到任何推送。我知道AWS实际上是在发布数据(如果我创建了电子邮件订阅,我会收到我发送的所有信息)。我也知道这些问题并不是由我的公司防火墙引起的——如果我试图通过4G实现这一点,它也会失败

我的日志中确实出现以下两个错误: 03-11 16:33:08.914 E/GcmReceiver(7749):无法解析目标意图服务,跳过类名强制 03-11 16:33:08.914 E/GcmReceiver(7749):传递消息时出错:未找到ServiceIntent

我不确定这些是否是原因。我还没有在网上找到解决这些问题的好方法


有人对尝试什么(或如何调试)有什么建议吗?老实说,我在这里有点不知所措。

您正在混合API,一方面您使用新的InstanceId API获取令牌,另一方面您使用wakefulbroadcastreceiver接收数据的旧方法,将您的接收器替换为来自GcmListenerService的派生类型,如下所示:

[Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]
public class SignalGCMReceiver : GcmListenerService
{

    public override void OnMessageReceived (string from, Bundle data)
    {
        Console.WriteLine(data.ToString());

    }
}
最后在清单上添加接收方(接收方由服务在内部实现):


您正在混合API,一方面您使用新的InstanceId API来获取令牌,另一方面您使用wakefulbroadcastreceiver接收数据的旧方法,将您的接收器替换为来自GcmListenerService的派生类型,如下所示:

[Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]
public class SignalGCMReceiver : GcmListenerService
{

    public override void OnMessageReceived (string from, Bundle data)
    {
        Console.WriteLine(data.ToString());

    }
}
最后在清单上添加接收方(接收方由服务在内部实现):



您的接收器服务在哪里?您需要一个从GcmListenerService派生的服务,该服务具有com.google.android.c2dm.intent.RECEIVE类型的意向过滤器。失败说明它找不到该服务的类。我确实有一个使用该类的实现,但它似乎没有帮助。但我需要同时拥有它和广播接收器吗?我的广播接收器已接收到这些类型的意图并将其传递给我的意图服务。但您没有发布广播接收器的代码,而广播接收器是接收消息的接收器,因此如果您有错误,它应该在那里。抱歉,您是对的,我也编辑了代码。你的接收服务在哪里?您需要一个从GcmListenerService派生的服务,该服务具有com.google.android.c2dm.intent.RECEIVE类型的意向过滤器。失败说明它找不到该服务的类。我确实有一个使用该类的实现,但它似乎没有帮助。但我需要同时拥有它和广播接收器吗?我的广播接收器已接收到这些类型的意图,并将其传递给我的意图服务。但您没有发布广播接收器的代码,而广播接收器是接收消息的接收器,因此如果您有错误,它应该在那里。抱歉,您是对的,我也编辑了该代码。