使用解析的 Android 推送在一段时间后停止工作

Posted

技术标签:

【中文标题】使用解析的 Android 推送在一段时间后停止工作【英文标题】:Android push using parse stops working after some time 【发布时间】:2015-03-18 22:37:14 【问题描述】:

我正在使用 Parse 在 android 上发送有针对性的推送通知。遵循教程几次(包括不眠之夜),它运行良好,但是在某些不可预测的事件中,应用程序的 android 用户停止接收通知。在 Google Play 上上传更新几个小时后肯定会发生这种情况。

为了在不上传到 Google Play 的情况下重现它,我将其范围缩小到当我从清单中更新应用程序的版本号并重新运行而不删除和重新安装时。但是,在清单中进行简单的更改使其再次工作。但是,该解决方案并不可靠,因为它会在几个小时后/上传到生产环境后再次停止工作。

我正在使用自定义 ParsePushBroadcastReceiver 来播放自定义声音。我正在使用 Google Play Services 5 进行位置更新。我正在订阅我在以后的活动中推送的频道。关于可能导致此类问题的任何想法?代码粘贴如下:

清单

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx.xxx"
    android:versionCode="19"
    android:versionName="3.077" >

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>
    <!-- GCM PERMISSIONS -->
    <permission android:name="com.xxx.xxx.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.xxx.xxx.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
    <uses-permission android:name="com.xxx.xxx.permission.MAPS_RECEIVE" />
    <application
        android:name="com.xxx.xxx.MyApplication"
        android:allowBackup="true"
        android:allowClearUserData="true"
        android:enabled="true"
        android:icon="@drawable/icon"
        android:logo= "@drawable/icon"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <uses-library android:name="com.google.android.maps" />

        <service android:name="com.xxx.xxx.xxxLocationService" />

         <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="xxxxxxxxxxx"/>
        <meta-data android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data android:name="com.parse.push.gcm_sender_id"
                    android:value="id:xxxxx" />
        <service android:name="com.parse.PushService" />
        <receiver android:name="com.parse.ParseBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>
        <receiver android:name="com.xxx.xxx.xxxBroadcastReceiver"
            android:exported="false">
            <intent-filter>
                <action android:name="com.parse.push.intent.RECEIVE" />
                <action android:name="com.parse.push.intent.DELETE" />
                <action android:name="com.parse.push.intent.OPEN" />
            </intent-filter>
        </receiver>
        <receiver android:name="com.parse.GcmBroadcastReceiver"
            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" />

                <!--
                  IMPORTANT: Change "com.parse.starter" to match your app's package name.
                -->
                <category android:name="com.xxx.xxx" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

应用类

public class MyApplication extends Application 
       @Override
       public void onCreate()
           Parse.initialize(this, "xxxxxx", "xxxxxx");
           ParseInstallation.getCurrentInstallation().saveInBackground();
       

依赖

dependencies 
    compile 'com.google.android.gms:play-services:5.+'
    compile 'com.google.code.gson:gson:2.3'
    compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
    compile 'com.android.support:support-v4:22.0.0'
    compile files('libs/PayPal_MPL.jar')
    compile files('libs/libGoogleAnalyticsServices.jar')
    compile 'com.parse.bolts:bolts-android:1.1.4'
    compile fileTree(dir: 'libs', include: 'Parse-*.jar')
    compile files('libs/Parse-1.8.3.jar')

ParsePushBroadcastReceiver

public class xxxBroadcastReceiver extends ParsePushBroadcastReceiver 

    @Override
    public void onReceive(Context context, Intent intent) 
        try 
            String jsonData = intent.getExtras().getString("com.parse.Data");
            JSONObject json = new JSONObject(jsonData);

            String title = null;
            if(json.has("title")) 
                title = json.getString("title");
            

            String message = null;
            if(json.has("alert")) 
                message = json.getString("alert");
            

            if(message != null) 
                generateNotification(context, title, message);
            
         catch(Exception e) 
            Log.e("NOTIF ERROR", e.toString());
        
    


    private void generateNotification(Context context, String title, String message) 
        Intent intent = new Intent(context, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0);

        NotificationManager mNotifM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if(title == null) 
            title = context.getResources().getString(R.string.app_name);
        

        final NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(context)
                        .setSmallIcon(R.drawable.icon)
                        .setContentTitle(title)
                        .setContentText(message)
                        .setStyle(new NotificationCompat.BigTextStyle()
                                .bigText(message))
                        .addAction(0, "View", contentIntent)
                        .setAutoCancel(true)
                        .setDefaults(new NotificationCompat().DEFAULT_VIBRATE)
                        .setSound(Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.whistle));

        mBuilder.setContentIntent(contentIntent);

        mNotifM.notify(randInt(100000000, 999999999), mBuilder.build());
    

    public static int randInt(int min, int max) 

        // NOTE: Usually this should be a field rather than a method
        // variable so that it is not re-seeded every call.
        Random rand = new Random();

        // nextInt is normally exclusive of the top value,
        // so add 1 to make it inclusive
        int randomNum = rand.nextInt((max - min) + 1) + min;

        return randomNum;
    


订阅频道

protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_jobs);

    ...

    ParsePush.subscribeInBackground("driver");

更新

这是我目前重现该问题的方式。我在调试模式下运行并且它可以工作,然后我更改应用程序的版本号并导出已签名的应用程序以进行生产(不运行)。我将该签名的 APK 安装到设备上(删除后)并且通知停止工作。似乎覆盖 ParsePushBroadcastReceiver 与它无关。如果我使用相同的版本号删除并在调试模式下重新运行,除非我更改清单中的某些内容,例如 BroadcastReceiver,否则它将无法工作。这是我设法重现它的方式,但是通知在到达 Google Play 时无论如何都会停止工作(现在再试一次)。我错过了什么?

【问题讨论】:

您是否尝试在 Parse Dashboard 的应用设置中将 Released in Production 开关设置为 ON? 是的,它已开启。可能是谷歌出于某种原因阻止了 GCM 的应用程序吗?我没有主意了。 您的onReceive 在版本号更改后再也不会被调用?另外,您可以共享任何日志吗?在纯 GCM 实现中(意味着没有 Parse),如果出现问题,响应错误会被发送回您的应用服务器。 【参考方案1】:

example implementation 中有这样的评论:

// Check if app was updated; if so, it must clear the registration ID
// since the existing registration ID is not guaranteed to work with
// the new app version.

我确定你会遇到这种情况。因此解决方案是在更新后注册您的应用程序。我想在您的情况下,最好的选择是查看PACKAGE_REPLACED 事件,您应该在那里再次注册您的应用程序。还请查看 this question 以了解其工作原理。

【讨论】:

以上是关于使用解析的 Android 推送在一段时间后停止工作的主要内容,如果未能解决你的问题,请参考以下文章

一段时间后,android后台服务停止

拟合模型时,内核在一段时间后停止工作

按钮声音在一段时间后停止

如何在一段时间后停止正在运行的方法执行? [复制]

在 GRU 层 Pytorch 中训练将在一段时间后停止

Spring boot REST服务在一段时间后停止