在Native Extension中创建的Pending Intent仅适用于Notification但不适用于Service

时间:2014-01-21 20:55:57

标签: android android-intent android-service android-notifications air-native-extension

我正在开发一款使用Air Native Extensions(ANE)的Android Air应用程序。从ANE我调用一个创建Pending Intent的函数,该函数传递给Notification。接下来,本机函数启动服务并将其传递给Pending Intent和Notification。这是该部分的代码:

public class StartServiceFunction implements FREFunction {

    @Override
    public FREObject call(FREContext context, FREObject[] args) {
        Log.d("MyApplicationStartServiceFunction", "call(StartService)");

        Context applicationContext = context.getActivity().getApplicationContext();

        try {
                String appPackageName = args[0].getAsString();
                String applicationID = args[1].getAsString();
                String notificationMessage = args[2].getAsString();
                String statusServiceURL = args[3].getAsString();
                String triggerResponse = args[4].getAsString();

                Intent appLaunchIntent = applicationContext.getPackageManager().getLaunchIntentForPackage(appPackageName);      
                PendingIntent pendingLaunchIntent = PendingIntent.getActivity(applicationContext, 0, appLaunchIntent, 0);

                int icon = context.getResourceId("drawable.notification_icon");

                Notification serviceNotification = new Notification.Builder(applicationContext)
                                                            .setContentTitle(applicationID)
                                                            .setContentText(notificationMessage)
                                                            .setSmallIcon(icon)
                                                            .setContentIntent(pendingLaunchIntent)
                                                            .build();
                Log.d("MyApplicationStartServiceFunction", "call(StartService): notification Created");

                Intent serviceIntent = new Intent(applicationContext, MyApplicationService.class);
                serviceIntent.putExtra("serviceNotification", serviceNotification);
                serviceIntent.putExtra("statusServiceURL", statusServiceURL);
                serviceIntent.putExtra("triggerResponse", triggerResponse);
                serviceIntent.putExtra("pendingLaunchIntent", pendingLaunchIntent);

                applicationContext.startService(serviceIntent);  
                Log.d("MyApplicationStartServiceFunction", "call(StartService): startService issued");

                return FREObject.newObject(true);
        } catch (Exception e) {
            Log.d("MyApplicationStartServiceFunction", "Exception: " + e.getMessage());
            e.printStackTrace();
        }

        try {
            return FREObject.newObject(false);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

这部分代码就像魅力一样。

接下来,当在服务中调用onStartCommand()方法时,我将Pending IntentNotification中的Intent作为参数传递给上述方法。获得通知的目的是将服务设置为它所执行的前台进程(startForeground()),并且还允许用户在他点击通知时重新输入应用程序。传递挂起意图的关键是,当满足某些条件时,服务可以激活它(Pending Intent)并使应用程序成为主要的可见进程。这是我用于此的代码(请记住,它的一部分被省略,因为它不是问题而且工作正常):

public class MyApplicationService extends Service implements TriggeredResponseListener {

        private Timer timer;
        private PendingIntent pendingLaunchIntent;
        private String statusServiceURL;
        private String triggerResponse;

        @Override
        public IBinder onBind(Intent arg0) {
                Log.d("MyApplicationService", "onBind()");
                return null;
        }

        @Override
        public void onCreate() {
                Log.d("MyApplicationService", "onCreate()");
                super.onCreate();
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                Log.d("MyApplicationService", "onStartCommand(): " + intent.toString());
                Notification serviceNotification = intent.getParcelableExtra("serviceNotification");            
                startForeground(1,serviceNotification);
                Log.d("MyApplicationService", "onStartCommand(): startForegroundService");

                pendingLaunchIntent = intent.getParcelableExtra("pendingLaunchIntent");
                statusServiceURL = intent.getStringExtra("statusServiceURL");
                triggerResponse = intent.getStringExtra("triggerResponse");
                Log.d("MyApplicationService", "onStartCommand(): getParcelableExtras");

                if(timer == null)
                {
                        timer = new Timer("Printer");
                        HttpServiceTask serviceTask = new HttpServiceTask(statusServiceURL, triggerResponse);
                        serviceTask.addEventListener(this);
                        timer.schedule(serviceTask, 0, 2000);
                        Log.d("MyApplicationService", "onStartCommand(): startTimer");
                }

                return START_REDELIVER_INTENT;
        }

        public void handleTriggeredResponseEvent(TriggeredResponseEvent eventObject) {
                Log.d("MyApplicationService", "handleEvent()");
                destroyTimer();
                HttpServiceTask serviceTask = eventObject.httpServiceTask;
                serviceTask.removeEventListener(this);
                Log.d("MyApplicationService", "handleEvent(): launching pendingLaunchIntent");
                try{
                        pendingLaunchIntent.send();
                } catch (Exception e) {
                        Log.d("MyApplicationService", "handleEvent(): " + e.getMessage());
                        e.printStackTrace();
                }                               
                this.stopSelf();
                Log.d("MyApplicationService", "handleEvent(): stopSelf");
        }

        private void destroyTimer() {
                if (timer != null){
                        timer.cancel();
                        timer = null;
                }
        }

        @Override
        public void onDestroy() {
                Log.d("MyApplicationService", "onDestroy():");
                destroyTimer();
                Log.d("MyApplicationService", "onDestroy(): destroyTimer():");
                super.onDestroy();
        }
}

该代码ALMOST工作正常。它适用于大多数情况,但不适用于每一种情况。

涉及与Pending Intent相关的操作的方法是handleTriggeredResponseEvent(),所以让我们关注那个问题。如您所见,当调用此处理程序时,将发送Pending Intent。请记住,它应与Notification完全相同,因为它是由同一Pending Intent制作的。

如果尚未从最近的应用程序列表中关闭Air mobile应用程序(按住Home按钮),Pending Intent将成功激活handleTriggeredResponseEvent()和Air应用程序将再次成为用户可见的主要应用程序。

从最近的应用程序列表中关闭Air mobile应用程序时出现问题。当满足条件并且调用方法handleTriggeredResponseEvent()时,一切都正确运行,即使pendingLaunchIntent.send()运行也没有抛出任何异常。唯一的区别是应用程序未启动。我只能看到一个黑屏(Air运行时启动?),但不能运行Air mobile应用程序。

另一方面,当我从“最近的应用程序列表”关闭Air应用程序并激活通知栏上的服务通知时,即使它使用与{{Pending Intent相同的handleTriggeredResponseEvent(),也会正确启动应用程序。 1}}方法。

我检查了所有Log语句,代码运行时没有任何错误,并且在所有方案中都以相同的方式运行。

这怎么可能?从Pending Intent方法发送的handleTriggeredResponseEvent()不应该与激活服务通知时发送的效果相同吗?

显然我错过了一些东西。它可能是Application Manifest XML中的内容吗?接下来是清单中服务的声明:

<application android:debuggable="true">
              <service android:enabled="true" android:exported="true" android:name="com.mycompany.myextension.services.MyService">    
                        <intent-filter>
                                 <action android:name="air.com.mycompany.myextension.DO_CUSTOM_ACTION"/>
                        </intent-filter>
                </service>
</application>

任何帮助都将深表感谢。提前谢谢。

编辑:LogCat上的错误

我可以捕获LogCat错误,它们在这里:

01-22 15:21:27.625: I/ActivityManager(381): Killing 25792:air.QOE/u0a122: remove task 
01-22 15:21:27.664: W/ActivityManager(381): Exception when starting activity air.QOE/.AppEntry 
01-22 15:21:27.664: W/ActivityManager(381): android.os.DeadObjectException 
01-22 15:21:27.664: W/ActivityManager(381): at android.os.BinderProxy.transact(Native Method) 
01-22 15:21:27.664: W/ActivityManager(381): at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:743) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.realStartActivityLocked(ActivityStack.java:821) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.startSpecificActivityLocked(ActivityStack.java:949) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:2321) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1862) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1837) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1411) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1356) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityStack.activityPaused(ActivityStack.java:1266) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:4609) 
01-22 15:21:27.664: W/ActivityManager(381): at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:401) 
01-22 15:21:27.664: W/ActivityManager(381): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1729) 
01-22 15:21:27.664: W/ActivityManager(381): at android.os.Binder.execTransact(Binder.java:367) 
01-22 15:21:27.664: W/ActivityManager(381): at dalvik.system.NativeStart.run(Native Method) 
01-22 15:21:27.726: I/ActivityManager(381): Process air.QOE (pid 25792) has died and restarted (pid 25900).

在乞讨时,似乎DeadObjectException告诉我没有任何活动来处理意图,但后来我添加了以下代码:

PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
Log.d("EasyControlService", "launchApplication(): Activities ready for intent: " + activities.size());
if (activities.size() == 0){
    Log.d("EasyControlService", "launchApplication(): there are no activities ready for intent");
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

表示活动仍然存在。

1 个答案:

答案 0 :(得分:1)

Sebastian,从我所看到的情况可能会发生这种情况,因为您在同一个过程中运行该服务。您甚至不需要Pending意图来启动应用程序,您可以按照常规意图执行此操作。您唯一需要做的就是让服务在一个单独的进程上运行。您可以在清单上的android:process=”:name_of_the_process”标记上添加<service>