SNS Mobile Push

房东的猫 提交于 2019-12-12 03:30:08

问题


I am currently developing an Android app in Xamarin. I am using AWS SNS Push and Google Cloud Messenger (GCM).

I've been following this walkthrough pretty closely: http://docs.aws.amazon.com/mobile/sdkforxamarin/developerguide/getting-started-sns-android.html

The code I've been working with is extremely similar to what's there. However, I have a Registration Intent Service that works as follows:

  [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;
            }
        }
    }
}

I start the Registration Intent Service explicitly with a StartService() call in the MainActivity OnCreate event handler. I made sure I set up all of the permissions called for in the documentation:

[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")]

I create most of my Android Manifest through the AssemblyInfo.cs and appropriate C# Attributes (e.g. the [Service] attribute). The only thing I explicitly declare in XML (other than the application) is as follows:

<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>

Here's the final manifest:

<?xml version="1.0" encoding="UTF-8"?>
<manifest android:installLocation="auto" android:versionName="1.0" android:versionCode="1" package="com.gcmmessaging" xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-sdk android:minSdkVersion="16"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<permission android:name="com.gcmmessaging.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="com.gcmmessaging.permission.C2D_MESSAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.SEND"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application android:name="mono.android.app.Application"
             android:allowBackup="true"
             android:debuggable="true"
             android:icon="@drawable/sns_icon_48"
             android:label="ProductName">
             <receiver android:name="com.google.android.gms.gcm.GcmReceiver"
                    android:permission="com.google.android.c2dm.permission.SEND"
                    android:exported="true">
                    <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>
            <meta-data android:name="com.google.android.gms.version"
                        android:value="@integer/google_play_services_version"/>
            <activity android:name="[ConfigurationName]"
                        android:label="Configuration"/>
            <receiver android:name="md503b8085957a5cb3d4167d0e7cbb2a6b0.GCMBootReceiver">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
            </receiver>
            <service android:name="md503b8085957a5cb3d4167d0e7cbb2a6b0.GCMIntentService" android:exported="false"/>
            <receiver android:name="md503b8085957a5cb3d4167d0e7cbb2a6b0.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
                <!-- It did occur to me to try to put all of these in a single  -->
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
                    <category android:name="com.gcmmessaging"/>
                    </intent-filter>
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
                    <category android:name="com.gcmmessaging"/>
                </intent-filter>
                <intent-filter>
                    <action android:name="com.google.android.gcm.intent.RETRY"/>
                    <category android:name="com.gcmmessaging"/>
                </intent-filter>
            </receiver>
            <activity android:name="[Activityname]" android:label="History"/>
            <service android:name="md503b8085957a5cb3d4167d0e7cbb2a6b0.MyInstanceIdListenerService" android:exported="false">
                <intent-filter>
                    <action android:name="com.google.android.gms.iid.InstanceID"/>
                </intent-filter>
            </service>
            <activity android:name="[ActivityName]" android:icon="@drawable/sns_icon_32" android:label="ProductName">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
            <service android:name="md503b8085957a5cb3d4167d0e7cbb2a6b0.RegistrationIntentService" android:exported="false"/>
            <receiver android:name="md5343e36a1bb0d551a047a1a24886e23d0.NetworkReachability_NetworkStatusChangeBroadcastReceiver"/>
            <provider android:name="com.google.android.gms.measurement.AppMeasurementContentProvider" android:exported="false" android:authorities="com.gcmmessaging.google_measurement_service"/>
            <service android:name="com.google.android.gms.measurement.AppMeasurementService" android:exported="false" android:enabled="true"/>
            <receiver android:name="com.google.android.gms.measurement.AppMeasurementReceiver" android:enabled="true">
                <intent-filter>
                    <action android:name="com.google.android.gms.measurement.UPLOAD"/>
                </intent-filter>
            </receiver>
            <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:authorities="com.gcmmessaging.mono.MonoRuntimeProvider.__mono_init__" android:initOrder="2147483647"/>
    <!--suppress ExportedReceiver-->
    <receiver android:name="mono.android.Seppuku">
        <intent-filter>
            <action android:name="mono.android.intent.action.SEPPUKU"/>
            <category android:name="mono.android.intent.category.SEPPUKU.com.gcmmessaging"/>
        </intent-filter>
    </receiver>
</application>
</manifest>

Here is my broadcast receiver:

[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 GCMBroadcastReceiver : WakefulBroadcastReceiver
{
    //private const string TAG = "PushHandlerBroadcastReceiver";

    public override void OnReceive(Context context, Intent intent)
    {
        Logging.LogMessage(context, "GCMBroadcastReceiver.OnReceive", "Received message", LogType.Debug);

        GCMIntentService.RunIntentInService(context, intent);
        SetResult(Result.Ok, null, null);

        Logging.LogMessage(context, "GCMBroadcastReceiver.OnReceive", "Ran intent service", LogType.Debug);
    }
}

I currently receive a GCM token and subscribe to GCM and SNS correctly. I checked the return codes there carefully and I'm definitely getting a valid-looking GCM token and my subscription shows up in SNS. My call to subscribe to GCM succeeds without throwing any exceptions. However, I don't actually receive any pushes. I know for a fact that AWS is, in fact, publishing the data (if I create an email subscription I receive everything I'm sending out). I also know that the issues aren't caused by my corporate firewall - if I try to do it over 4G it fails too.

I do get the two following errors in my logs: 03-11 16:33:08.914 E/GcmReceiver( 7749): Failed to resolve target intent service, skipping classname enforcement 03-11 16:33:08.914 E/GcmReceiver( 7749): Error while delivering the message: ServiceIntent not found.

I'm not sure if these are the cause or not. I haven't been able to find a good resolution to these online yet.

Anyone have any suggestions on what to try (or how to go about debugging this)? I'm truthfully at a bit of a loss here.


回答1:


You are mixing API's, for one side you use the new InstanceId API to get the token and in other you use the old way of receiving data with a wakefulbroadcastreceiver, replace your receiver with a derived type from GcmListenerService, something like this:

[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());

    }
}

And finally add the receiver on the manifest (the receiver is implemented internally by the service):

    <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="@PACKAGE_NAME@" />
        </intent-filter>
    </receiver>


来源:https://stackoverflow.com/questions/35949757/sns-mobile-push

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!