对于某些应用程序,getLaunchIntentForPackage为空

41 人关注

我正在建立一个服务,从Android TV或Fire TV向手机发送已安装的应用程序列表。然后手机发回它想启动的应用程序的软件包名称,服务就会启动它。

这是创建列表的代码

public List<InstalledApp> GetInstalledApps(boolean isAndroid) {
    PackageManager pm = getPackageManager();
    List<ApplicationInfo> allPackages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
    List<InstalledApp> userPackages = new ArrayList<InstalledApp>();
    for (ApplicationInfo packageInfo : allPackages) {
        if (isSystemPackage(packageInfo)) continue;
        InstalledApp app = new InstalledApp();
        app.setPackageName(packageInfo.packageName);
        app.setAppName(pm.getApplicationLabel(packageInfo).toString());
        if (!isAndroid) {
            app.setIcon(pm.getApplicationIcon(packageInfo));
        app.setAccentColor(getAccentColor(pm.getApplicationIcon(packageInfo)));
        userPackages.add(app);
    return userPackages;

我是这样启动应用程序的

public void launchApp(String packageName) {
    PackageManager pm = getPackageManager();
    Intent intent = pm.getLaunchIntentForPackage(packageName);
    startActivity(intent);

在Fire TV上,一切工作都很完美,但在Android TV上,许多应用程序的意图总是无效。这些只是其中的一部分。

  • com.haystack.android
  • com.netflix.ninja
  • tv.pluto.android
  • com.bamnetworks.mlbtv
  • 然而,用同样的代码,这些应用程序就能正常工作。

  • com.hulu.livingroomplus
  • com.sling
  • com.frogmind.badland
  • com.songza.tv
  • 有谁能提供一些关于我可能做错了什么的见解吗?

    EDIT: 我也试过这样做,但我得到的例外情况是

    android.content.ActivityNotFoundException。No Activity found to handle Intent { cat=[android.intent.category.LEANBACK_LAUNCHER] flg=0x10000000 pkg=com.netflix.ninja }

    public void launchApp(String packageName) {
        Intent intent = new Intent();
        intent.setPackage(packageName);
        intent.addCategory("android.intent.category.LEANBACK_LAUNCHER");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    

    EDIT 2:

    这是对我有用的代码。

    public void launchApp(String packageName) {
        Intent intent = new Intent();
        intent.setPackage(packageName);
        PackageManager pm = getPackageManager();
        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
        Collections.sort(resolveInfos, new ResolveInfo.DisplayNameComparator(pm));
        if(resolveInfos.size() > 0) {
            ResolveInfo launchable = resolveInfos.get(0);
            ActivityInfo activity = launchable.activityInfo;
            ComponentName name=new ComponentName(activity.applicationInfo.packageName,
                    activity.name);
            Intent i=new Intent(Intent.ACTION_MAIN);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            i.setComponent(name);
            startActivity(i);
        
    5 个评论
    请记住,在安卓电视上, LEANBACK_LAUNCHER 是启动器的类别,而不是像手机和平板电脑上的 LAUNCHER 。我的猜测是,这些应用程序没有 LAUNCHER 活动,而且 getLaunchIntentForPackage() 只对 LAUNCHER 有效,而不是 LEANBACK_LAUNCHER
    我试着为意图手动设置包的名称,并添加类别 android.intent.category.LEANBACK_LAUNCHER ,但它仍然不工作。我知道Netflix有一个 LEANBACK_LAUNCHER 。我的目标是SDK17-21版本,如果这很重要的话。
    "我试着为意图设置包名,并添加一个android.intent.category.LEANBACK_LAUNCHER的类别,但它仍然不工作" -- 我不知道你在你现有代码的背景下是什么意思。欢迎你使用 queryIntentActivities() 来查找所有 LEANBACK_LAUNCHER 的活动。这(尽管有 LAUNCHER )是主屏幕所做的,而不是使用 getLaunchIntentForPackage() )。这里有一个主屏幕式启动器的例子。 github.com/commonsguy/cw-omnibus/tree/master/Introspection/...
    非常感谢编辑2!我已经建立了一个启动器,但由于pm.getLaunchIntentForPackage返回null,所以无法从中启动另一个启动器。你的代码在这个问题上非常有效。
    android
    android-tv
    amazon-fire-tv
    nexus-player
    Jeremy Roberts
    Jeremy Roberts
    发布于 2015-05-26
    5 个回答
    Billda
    Billda
    发布于 2015-05-27
    已采纳
    0 人赞同

    自从安卓11以来,有一个行为变化,一些应用程序不会提供这些信息,除非你在AndroidManifest中添加 queries 标签,例如

        <queries>
            <package android:name="app.i.want.to.query" />
        </queries>
    

    Refer here for more info

    这是教程中没有提到的秘密
    我在清单中输入了这个文本,现在出现了错误,而且没有被删除。
    don't do this !
    This worked actually for me. "If your app targets Android 11 (API level 30) or higher and needs to interact with apps other than the ones that are visible automatically, add the <queries> element in your app's manifest file. Within the <queries> element, specify the other apps by package name."
    More info - android-developers.googleblog.com/2020/07/...
    CommonsWare
    CommonsWare
    发布于 2015-05-27
    0 人赞同

    要创建一个主屏幕风格的启动器,不要寻找应用程序,然后试图为每个应用程序获取启动 Intents 。寻找可启动的活动,在 PackageManager 上使用 queryIntentActivities()

    例如,这项活动(来自 这个样本项目 )使用这种技术实现了一个主屏幕风格的启动器。

    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. From _The Busy Coder's Guide to Android Development_ http://commonsware.com/Android package com.commonsware.android.launchalot; import android.app.ListActivity; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import java.util.Collections; import java.util.List; public class Launchalot extends ListActivity { AppAdapter adapter=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); PackageManager pm=getPackageManager(); Intent main=new Intent(Intent.ACTION_MAIN, null); main.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> launchables=pm.queryIntentActivities(main, 0); Collections.sort(launchables, new ResolveInfo.DisplayNameComparator(pm)); adapter=new AppAdapter(pm, launchables); setListAdapter(adapter); @Override protected void onListItemClick(ListView l, View v, int position, long id) { ResolveInfo launchable=adapter.getItem(position); ActivityInfo activity=launchable.activityInfo; ComponentName name=new ComponentName(activity.applicationInfo.packageName, activity.name); Intent i=new Intent(Intent.ACTION_MAIN); i.addCategory(Intent.CATEGORY_LAUNCHER); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); i.setComponent(name); startActivity(i); class AppAdapter extends ArrayAdapter<ResolveInfo> { private PackageManager pm=null; AppAdapter(PackageManager pm, List<ResolveInfo> apps) { super(Launchalot.this, R.layout.row, apps); this.pm=pm; @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView==null) { convertView=newView(parent); bindView(position, convertView); return(convertView); private View newView(ViewGroup parent) { return(getLayoutInflater().inflate(R.layout.row, parent, false)); private void bindView(int position, View row) { TextView label=(TextView)row.findViewById(R.id.label); label.setText(getItem(position).loadLabel(pm)); ImageView icon=(ImageView)row.findViewById(R.id.icon); icon.setImageDrawable(getItem(position).loadIcon(pm));

    在安卓电视设备上,你还应该搜索 LEANBACK_LAUNCHER 活动,因为这是安卓电视使用的,而电视专用的APK可能没有常规的 LAUNCHER 活动,或者至多有一个不一定适合在电视上使用的活动。

    我试着修改了你的答案,在这里,但它失败了。你能建议一个答案吗? stackoverflow.com/questions/38856092/...
    非常感谢!我已经建立了一个发射器,但却无法从该发射器启动另一个发射器,因为pm.getLaunchIntentForPackage返回了null。我已经建立了一个启动器,但由于pm.getLaunchIntentForPackage返回null,所以无法从中启动另一个启动器。你的代码对这个问题的解决很有帮助。
    为什么要在用于启动活动的意图上(在onListItemClick()中)同时设置组件和动作及类别?设置一个组件将使意图明确,不需要动作或类别。
    @PiotrŚmietana:我们开始的活动可能是查看行动或类别,以确定要做什么。有时,开发者在 <activity> 上有多个 <intent-filter> 元素,需要检查传入的 Intent 来区分各种选项。因此,如果你创建一个 Intent 来匹配活动的 <intent-filter> ,那是最安全的。 设置该组件。这样一来,显式的 Intent 被保证到你想要的地方,但活动得到它可能需要的隐式动作+类别。
    这实际上就是 getLaunchIntentForPackage 在引擎盖下所做的事情。 android.googlesource.com/platform/frameworks/base/+/refs/heads/... 唯一的区别是它在 Intent (你称之为 main )上调用 setPackage ,以确保查询到的意图只是那些需要的特定包。
    lunarzshine
    lunarzshine
    发布于 2015-05-27
    0 人赞同

    在安卓11中,你只能用 getInstalledApplications() 获得有限数量的包名,而且你只能通过使用 getInstalledApplications() ,并且你只能通过使用 getLaunchIntentForPackage()

    将此权限添加到你的Android Manifest文件中,以获得所有应用程序的包名和意图。

    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
    

    如果你只想为有限数量的应用程序设置意图,你应该在你的安卓清单文件中使用查询。

    <queries>
        <package android:name="packageName" />
    </queries>
        
    s-hunter
    s-hunter
    发布于 2015-05-27
    0 人赞同

    我在调用 getLaunchIntentForPackage(packageName) 时也遇到了同样的错误。通过在清单文件中的启动器活动的intent-filter标签中添加这个内容,它被修复了。

    <category android:name="android.intent.category.LAUNCHER" />
    

    当在Android Studio中创建一个新的电视应用程序时,它没有将上述内容作为默认值,而是在清单文件中的启动器活动的intent-filter标签中将此作为默认值。

    <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
        
    Peter
    Peter
    发布于 2015-05-27
    0 人赞同
        Intent launchIntent = null;
                            launchIntent = context.getPackageManager().getLeanbackLaunchIntentForPackage(pkgName);
                        } catch (java.lang.NoSuchMethodError e){
                        if (launchIntent == null) launchIntent = context.getPackageManager().getLaunchIntentForPackage(pkgName);
                    if (launchIntent != null)  {
                        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);