在本机扩展创建待定意图只能从通知而不是服务中 [英] Pending Intent created in Native Extension works only from Notification but not within Service

查看:328
本文介绍了在本机扩展创建待定意图只能从通知而不是服务中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在开发Android的空中移动应用程序,它使用AIR本机扩展(ANE)。从ANE我呼吁创建被传递到通知挂起的意图的功能。其次,本地功能启动的服务,并将其传递挂起的意图和通知。这里的code表示的部分:

I’m developing an Air mobile application for Android which uses Air Native Extensions (ANE). From the ANE I call a function that creates a Pending Intent which is passed to a Notification. Next, the native function starts a service and passes it the Pending Intent and the Notification. Here’s the code for that part:

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

在code的那部分就像一个魅力。

That part of the code works like a charm.

接下来,当 onStartCommand()方法是在服务中调用,我找回了待意图通知意图作为参数所提到的方法传递。具有通知的要点是将服务设置为前台进程( startForeground()),这确实如此,也让用户重新输入应用程序时,他打通知。通过挂起意向的一点是,在满足一定条件下,该服务可以激活它(挂起意图),并应用为主要可见的过程。这里是code我使用为(请记住,它的一部分被省略,因为它不是一个问题,它的工作确定):

Next, when the onStartCommand() method is invoked within the service, I retrieve the Pending Intent and the Notification from the Intent passed as an argument to the mentioned method. The point of having the notification is to set the service as a foreground process (startForeground()), which it does, and also let the user reenter the application when he hits the notification. The point of passing the pending intent is that when certain conditions are met, the service can activate it (Pending Intent) and make the application as the main visible process. Here is the code I use for that (please keep in mind that part of it is omitted since it’s not a problem and it’s working ok):

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

这code ALMOST工作正常。它在大多数的情况下,而不是在他们每个人的伟大工程。

That code ALMOST works fine. It works great on most of the situations but not on every one of them.

涉及有关的行动待定意图的方法 handleTriggeredResponseEvent()让我们专注于那一个。正如你所看到的,当这个处理器被调用时,待意图发送。请记住,它应该做同样的事情在通知,因为它是从同一个发待意图

The method involving the actions related to the Pending Intent is handleTriggeredResponseEvent() so let’s focus on that one. As you can see, when this handler gets called, the Pending Intent is sent. Remember that it should do exactly the same thing as the Notification since it was made from the same Pending Intent.

如果空中移动应用一直没有从最近的应用程序列表关闭(按住首页按钮),在待意图将成功地从 handleTriggeredResponseEvent()被激活,AIR应用程序将是对用户可见的主要应用一次。

If the Air mobile application hasn’t been closed from the Recent Applications List (hold down Home button), the Pending Intent will be activated successfully from the handleTriggeredResponseEvent() and the Air application will be the main application visible to the user once again.

当你从最近的应用程序列表关闭空气移动应用程序的问题就来了。当条件满足和方法 handleTriggeredResponseEvent()被调用,一切都在正确运行,即使是 pendingLaunchIntent.send()运行没有抛出任何异常。唯一的区别是,该应用程序不启动。我只能看到黑屏(AIR运行时推出?),但不是空气移动应用程序的运行。

The problem comes when you close the Air mobile application from the Recent Applications List. When the conditions are met and the method handleTriggeredResponseEvent() is invoked, everything is ran correctly, even the pendingLaunchIntent.send() runs without throwing any exceptions. The only difference is that the application is not launched. I can only see a black screen (Air runtime launched?) but not the Air mobile application running.

在另一面,当我关闭从最近的应用程序列表中的AIR应用程序和激活我的通知栏上的服务通知,将应用程序正常启动,尽管它使用同样的待意图 handleTriggeredResponseEvent()方法。

On another side, when I closed the Air application from the Recent Applications List and I activate the service notification on the notifications bar, the application gets launched correctly, even though it uses the same Pending Intent as the handleTriggeredResponseEvent() method.

我检查所有的日志报表及code是没有任何错误,并在所有情况下以同样的方式运行。

I checked all the Log statements and the code is running without any errors and on the same way in all scenarios.

怎么能这样呢?不应该在待意图 handleTriggeredResponseEvent()方法发送具有相同效果差来的时候通知该服务被激活?

How can this be? Shouldn’t the Pending Intent sent from the handleTriggeredResponseEvent() method have the same effect as the one sent when the notification of the service is activated?

显然,我失去了一些东西。难道是应用程序清单XML中的东西吗?其次是服务的清单中声明:

Clearly I am missing something. Could it be something within the Application Manifest XML? Next is the declaration of the service within the manifest:

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

任何帮助会深深AP preciated。先谢谢了。

Any help will be deeply appreciated. Thanks in advance.

我能捕捉到LogCat中的错误,并在这里,他们是:

I could capture the LogCat errors and here they are:

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告诉我,没有发现任何活动,以处理这个意图,但后来,我加入了以下code:

At the begging it seemed that the DeadObjectException was telling me that there weren't any activities to handle the intent, but later, I added the following code:

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

这意味着该活动仍present

which means that the activity is still present.

推荐答案

塞巴斯蒂安,从我所看到的这可能是发生,因为你是在同一个进程中运行的服务。你甚至都不需要待意图启动应用程序,你可以只用一个普通的意图去做。你所要做的唯一一件事就是让一个单独的进程中运行的服务。你这样做,添加的android:在&LT:name_of_the_process;服务&gt;在清单标记过程=。

Sebastian, from what I can see this probably is happening because you are running the service in the same process. You don’t even need a Pending intent to launch the application, you could just do it with a regular intent. The only thing you have to do is to make the service ran on a separate process. You do that adding the android:process=":name_of_the_process" on the <service> tag on the manifest.

这篇关于在本机扩展创建待定意图只能从通知而不是服务中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆