【问题标题】:AIR Native Extension - Starting an Android Background ServiceAIR 原生扩展 - 启动 Android 后台服务
【发布时间】:2013-01-31 22:19:13
【问题描述】:

我正在开发一个需要启动后台服务的 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 都对这个问题保持沉默。

【问题讨论】:

  • 您是否将扩展定义添加到air xml文件中? com.freshplanet.AirFacebook
  • 是的,定义在那里。扩展加载完美,它只是 Android 类加载器找不到 Service 类,因为“air”。前缀被添加到特定于“空气”的扩展的所有类中。请参阅下面的答案 #2!

标签: android service air adobe air-native-extension


【解决方案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 更加便携。希望这是有道理的。

【讨论】:

  • 你几乎完全正确!!我已经弄清楚了一些事情(关于 Android 上的 AIR,请阅读以下内容:)。
【解决方案2】:

我已经输入了这个问题并回答了它,因为我花了很长时间才弄清楚到底需要什么,而且我希望为许多其他开发人员省去一些严重的麻烦。

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

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

Adobe AIR 原生扩展规则

规则 1。 代码签名证书包必须与 app.xml 中的应用程序 ID 匹配 所以如果证书包是com.my.company,那么air app id一定是&lt;id&gt;com.my.company&lt;/id&gt;

规则 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);

【讨论】:

  • 是的,虽然只是一些事情,但我绝对建议您在清单中完全确定本地类的范围。否则,如果您尝试在不同的应用程序中使用它,应用程序 ID 将会更改,并且您的课程将无法正确找到。您的服务必须位于同一个包中,您只需在添加内容中正确确定其范围即可。
  • 对于非航空服务,这是完全正确的。但是,如果您尝试运行属于 AIR 的 NativeExtension 的一部分的服务,则完全范围的包名称与 .air 前缀不匹配,并且该服务仍然不会运行。因此,如果我有 com.my.company.TestService,我仍然会收到找不到“air.com.my.company.TestService”的错误。
  • 我已经用更多细节更新了我的答案,因为就代码的可重用性而言,您的解决方案并不是最好的。
  • 抱歉,我不同意这些规则。规则 1,app Id 可以是任何你想要的。如果它向您显示 com.my.company 会更好,但它会在没有它的情况下运行。规则2:Android加空。到您的软件包安装,但您不需要添加到您的服务 xml 条目。使它对我有用的是包括标签 enabled=true 和exported=true 像这样:
  • 感谢 Delcasda 的加入,你能发布你的 android manifest 来澄清一下吗?
【解决方案3】:

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

instance.init(context.getActivity());

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

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

现在它可以工作了。

【讨论】:

    猜你喜欢
    • 2012-10-09
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    相关资源
    最近更新 更多