0

我正在开发一个需要启动后台服务的 AIR 本机扩展。

我尝试了不同的启动服务的方法。

这是我的 AIR Android 清单部分(来自我的 -app.xml 文件)

//AIR android manifest section
<manifest android:installLocation="auto">
    <application>
        <activity android:name=".TestActivity">
            <intent-filter>
                <action android:name=".TestActivity"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

    <service android:name=".TestService">
    <intent-filter>
        <action android:name="test.default.service"/>
    </intent-filter>
    </service>
    </application>
</manifest>

服务类与活动在同一个包中。Activity 运行得很好,在 Activity 的 onStart() 方法中,我尝试使用以下方法启动服务:

方法一:

import android.app.Activity;

public class TestActivity extends Activity
{
    @Override
    protected void onStart()
    {
        super.onStart();
        Intent intent = new Intent("test.default.service");

        //clearly the classes are available because this compiles!
    intent.setClass(TestActivity.this, TestService.class);

        startService(intent);
    }
}

结果:

Unable to start service Intent { act=test.default.service cmp=air.com.my.company/com.my.company.TestService } U=0: not found

方法二:

import android.app.Activity;

public class TestActivity extends Activity
{
    @Override
    protected void onStart()
    {
        super.onStart();

        //start a service with intent
        startService(new Intent("test.default.service"));
    }
}

结果:

FATAL EXCEPTION: main
java.lang.RuntimeExeption: Unable to instantiate service air.com.my.company.TestService:
java.lang.ClassNotFoundException: 
Didn't find class "air.com.my.company.TestService" on path: /data/app/air.com.my.company-1.apk

问题似乎是那个“空气”。尝试启动服务时,在包名称前加上前缀。在运行我自己的自定义服务时,如何解决包名称的这种混乱?

我一直在讨论堆栈溢出,以及 Adob​​e 的论坛,似乎无法找到解决这个问题的完整方法。

还有一些其他的帖子涉及这个主题,但没有一个提供真正的运行解决方案和源代码。

我已将其缩减为最简单的情况,以确保没有导致问题的额外移动部件。

有关如何从在 AIR 中运行的扩展上下文启动 Android 服务的任何官方信息都会有所帮助。似乎连 Adob​​e 都对这个问题保持沉默。

4

3 回答 3

1

我认为您需要使用包名称在清单添加中完全确定服务类的范围:

...
<service android:name="com.my.company.TestService">

不知道它是否会起作用。我知道普通的 Android 会正确地预先设置类,但 AIR 应用程序得到了普及。前缀可能会导致您的问题。

更新:

我们实际上使用我们的几个原生扩展来做到这一点,所以我知道这是正确的。

使用完全范围的类名声明服务不使用点速记符号,这是您遇到问题的地方。使用点简写,Android 将假定该类在您的应用程序包中,在 AIR 应用程序下是

air.com.my.company

您这样做的方式意味着您的 ANE 将无法在具有不同应用程序 ID 的另一个应用程序中工作!

默认情况下,另一个 AIR 应用程序将查找

air.com.other.company.TestService 

因此,留下速记符号将意味着此应用程序将找不到您的服务/活动:

air.com.my.company.TestService

正确的方法是在您的本机代码中使用干净的包名称,例如 com.company.nativepackage,然后将其包含在清单中,如下所示:

<application>
    <activity android:name="com.company.nativepackage.TestActivity">
        <intent-filter>
            <action android:name="TestActivity"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>

    <service android:enabled="true" android:exported="true" android:name="com.company.nativepackage.TestService">    
        <intent-filter>
            <action android:name="air.com.my.company.DO_CUSTOM_ACTION"/>
        </intent-filter>
    </service>
</application>

这将适用于任何应用程序,并使您的 ANE 更加便携。希望这是有道理的。

于 2013-02-02T23:38:03.897 回答
0

我已经输入了这个问题并回答了它,因为我花费了大量时间来找出确切的要求,并且我希望为许多其他开发人员节省一些严重的头痛。

上面显示的 android manifest 非常好。上面显示的代码(在两种方法中)都很好。

问题在于 AIR 应用程序的签名证书和包名称。

Adobe AIR 原生扩展规则

规则 1. 代码签名证书包必须与您的 app.xml 中的应用程序 id 匹配,因此如果证书包是com.my.company,那么空中应用程序 id 必须是<id>com.my.company</id>

规则 2. 使用 ADT 为 android 打包原生扩展时,会在您的包名称中添加一个前缀,使其看起来像air.com.my.company.

当 Android ActivityManager 尝试运行您的服务时,它会在air.com.my.company. 因此,Service 类必须存在于您的 java 代码中的同一个包中(包括“air”前缀)。我的 TestService 类现在定义为air.com.my.company.TestService

使用以下清单,它运行得很好!

<application>
    <activity android:name=".TestActivity">
        <intent-filter>
            <action android:name="TestActivity"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>

    <service android:enabled="true" android:exported="true" android:name=".TestService">    
        <intent-filter>
            <action android:name="air.com.my.company.DO_CUSTOM_ACTION"/>
        </intent-filter>
    </service>
</application>

而且...这是我调用服务的方式。

Intent intent = new Intent("air.com.my.company.DO_CUSTOM_ACTION");
intent.setClass(currentContext, TestService.class);
currentContext.startService(intent);
于 2013-02-04T17:48:29.673 回答
0

对我来说,唯一的变化是我传递给原生包的上下文。就我而言,我的本机代码公开了一些 init(context) 方法,我最初是这样使用它的:

instance.init(context.getActivity());

这给了我“无法找到服务”错误。所以我把它改成:

instance.init(context.getActivity().getApplicationContext());

现在它可以工作了。

于 2013-04-09T06:17:05.863 回答