Android 调用第三方 APP

时间:2024-03-21 18:13:36

本文导读

  • 如果想要在 App 1 中调用 App 2 的 Activity1,则操作流程如下:
  • 1)首先被调用的 App 2 中要声明 Activity1 是可以被启动的 或者 Activity 是对外可见的

1.1、声明 Activity1 可以被启动,只需在 AndroidManifest.xml 文件中声明为程序入口即可:

        <activity android:name=".Activity1">
            <intent-filter>
                <!--声明这个活动被用做应用程序的程序入口-->
                <action android:name="android.intent.action.MAIN" />
                <!--声明应用程序可以通过设备启动器的图标来启动-->
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-

1.2、声明 Activity1 是对外可见的,同样在 AndroidManifest.xml 文件中声明 即可:

<activity
    android:name=".Activity1"
        android:screenOrientation="portrait"
        <!--声明对外可见-->
        android:exported="true">
</activity>

2)然后 App 1 要知道App 2 的package Name(包名)——此时 App 2 声明 Activity1 可以被启动。如果 App 2 的 Activity1 不是APP 启动的入口 Activity,即无 “android.intent.category.LAUNCHER ” 属性,此时还需要知道 Activity1 的名称。

启动第三方 APP 的核心代码:

String mPackageName="com.demo.app";
String mActivityName="com.demo.app.Activity1";
Intent intent=new Intent();
intent.setComponent(new ComponentName(mPackageName,mActivityName));
startActivityForResult(intent,1);

  • 对 android.intent.action.MAIN 和 android.intent.category.LAUNCHER 的简单理解:
  1. android.intent.action.MAIN:表明该 Activity 可以作为 APP 入口启动,一个 APP 可以有多个入口,例如微信的主界面(用户点击进入)和微信的支付界面(第三方调用进入)
  2. android.intent.category.LAUNCHER:表明该 Activity 可在桌面显示(点击APP图标就会触发此Activity)

调用操作

获取系统所有应用信息

  • 需求分析:当手机上点击 "开始" 后,控制台输出右侧所示的信息,即手机中已经安装的所有 APP 的包名。

Android 调用第三方 APP

  • 布局文件 activity_main.xml 文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/btnStart"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:text="开 始" />
</android.support.constraint.ConstraintLayout>
  • 主活动 MainActivity.java 文件内容如下:
package com.lct.www.yuan;

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    /**
     * buttonStart:开始按钮
     */
    private Button buttonStart;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindView();
    }
    private void bindView() {
        /**
         * 为开始按钮绑定但即使事件
         */
        buttonStart = findViewById(R.id.btnStart);
        buttonStart.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("Wmx Logs::", "开始按钮被点击了 id = " + v.getId() + "线程 = " + Thread.currentThread().getName());

                /** android.content.pm.PackageManager:包管理器
                 */
                final PackageManager packageManager = MainActivity.this.getPackageManager();

                /**getInstalledPackages(@PackageInfoFlags int flags):返回当前用户在手机上安装的应用包名
                 * flags:0 表示不接受任何参数,其它参数都带有限制
                 * MATCH_UNINSTALLED_PACKAGES:表示即使应用被 uninstall 了,但只要保留了数据,也能被搜出来
                 */
                List<PackageInfo> packageInfoList = packageManager.getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES);

                /**
                 * 循环获取 APP 包名
                 */
                if (packageInfoList != null) {
                    for (int i = 0; i < packageInfoList.size(); i++) {
                        String packName = packageInfoList.get(i).packageName;
                        Log.i("Wmx logs::", i + " packageName >>" + packName);
                    }
                    Log.i("Wmx Logs::", "输出结束....");
                }
            }
        });
    }
}

控制台输出如下:

I/Wmx Logs::: 开始按钮被点击了 id = 2131165218线程 = main
I/Wmx logs::: 0 packageName >>cn.nubia.browser
              1 packageName >>com.yulore.framework
              2 packageName >>cn.nubia.calculator2.preset
              3 packageName >>com.android.providers.telephony
              4 packageName >>cn.nubia.presetpackageinstaller
              5 packageName >>com.android.providers.calendar
       .........................
              14 packageName >>cn.nubia.musicpicker.preset
              15 packageName >>cn.nubia.alipayauthprovider
              16 packageName >>com.android.documentsui
       .........................
              30 packageName >>cn.nubia.bootanimationinfo
              31 packageName >>cn.nubia.setupwizard
              32 packageName >>com.qualcomm.qti.auth.fidocryptoservice
       .........................
              43 packageName >>com.qti.qualcomm.datastatusnotification
              44 packageName >>cn.nubia.zbiglauncher.preset
              45 packageName >>android
              46 packageName >>com.qualcomm.wfd.service
              47 packageName >>cn.nubia.neoshare
       .........................
              50 packageName >>cn.nubia.databackup

       .........................

  • 除了使用 getInstalledPackages 同理也可以使用 getInstalledApplications 方法,如下所示:
                PackageManager packageManager = getPackageManager();
                /**getInstalledApplications(@ApplicationInfoFlags int flags):返回已安装的所有应用程序包的列表
                 * flags:0 表示不接受任何参数,其它参数都带有限制
                 * MATCH_UNINSTALLED_PACKAGES:表示即使应用被 uninstall 了,但只要保留了数据,也能被搜出来
                 */
                List<ApplicationInfo> applicationInfoList = packageManager.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES);
                /**
                 * 循环获取 APP 包名
                 */
                if (applicationInfoList != null && applicationInfoList.size() > 0) {
                    for (int i = 0; i < applicationInfoList.size(); i++) {
                        String packageName = applicationInfoList.get(i).packageName;
                        Log.i("Wms logs::", "packageName=" + packageName);
                    }
                }
  • 此时控制台输出,结果是一样的:

I/Wmx Logs::: 开始按钮被点击了 id = 2131165218线程 = main
I/Wms logs::: packageName=cn.nubia.browser    
I/Wms logs::: packageName=com.yulore.framework    
              packageName=cn.nubia.calculator2.preset    
              packageName=com.android.providers.telephony    
       .........................
              packageName=com.android.wallpapercropper   
              packageName=cn.nubia.video  
              packageName=com.quicinc.cne.CNEService   
              packageName=cn.nubia.musicpicker.preset   
              packageName=cn.nubia.alipayauthprovider    

...............................................

常见的有:

com.tencent.mm      ——腾讯微信
com.youdao.dict     ——网易有道
com.tencent.mobileqq    ——腾讯 QQ
com.tencent.news    ——腾讯新闻
com.sina.weibo      ——微博
com.taobao.trip     ——飞猪

Android 调用第三方 APP

启动第三方 APP

  • 上面已经知道了如何获取手机中安装好的所有的应用的 包名,因为 Android 应用的包名必须在 Google 上唯一的,所以启动 第三方 APP 最简单方式就是根据它的 包名,核心代码如下:
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage("被启动的包名");
startActivity(intent );
  • 此种方式启动时,注意事项如下:
  1. 当调用的 APP(如下面的yuan)在最前端,被调用的第三方 APP 未启动时,则会被启动到最前端显示
  2. 当调用的 APP(如下面的yuan)在最前端,被调用的第三方 APP 已经在后台启动时,则会被切换到最前端显示
  3. 当调用的 APP(如下面的yuan)在后台运行,被调用的第三方 APP 未启动时,则会被启动到最前端显示
  4. 当调用的 APP(如下面的yuan)在后台运行,被调用的第三方 APP 也在后台运行时,则不会有任何效果
  • 效果如下:当点击 "开始按钮"后,启动手机上的微博(包名com.sina.weibo),然后为了对比,启动一个不存在/未安装的 app,此时显示 "启动的 APP 未 安装"

Android 调用第三方 APP

  • 布局文件 activity_main.xml 文件仍然采用之前的内容,主活动 MainActivity.java 文件内容更新如下:
package com.lct.www.yuan;

import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    /**
     * buttonStart:开始按钮
     */
    private Button buttonStart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindView();
    }

    private void bindView() {
        /**
         * 为开始按钮绑定但即使事件
         */
        buttonStart = findViewById(R.id.btnStart);
        buttonStart.setOnClickListener(new Button.OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.i("Wmx Logs::", "开始按钮被点击了 id = " + v.getId() + "线程 = " + Thread.currentThread().getName());

                /**
                 * 启动手机上 微博 APP (包名 com.sina.weibo)
                 * 故意启动错误一个 com.sina.weibo1 这是不存在的
                 */
                startLocalApp("com.sina.weibo");
                startLocalApp("com.sina.weibo1");
            }
        });
    }

     /**
     * 启动本地安装好的第三方 APP
     * 注意:此种当时启动第三方 APP 时,如果第三方 APP 当时没有运行,则会启动它
     * 如果被启动的 APP 本身已经在运行,则直接将它从后台切换到最前端
     *
     * @param packageNameTarget :App 包名、如
     *                          微博 com.sina.weibo、
     *                          微信 com.tencent.mm、
     *                          QQ com.tencent.mobileqq、
     *                          腾讯新闻 com.tencent.news
     */
    private void startLocalApp(String packageNameTarget) {
        if (appIsExist(packageNameTarget)) {
            PackageManager packageManager = getPackageManager();
            Intent intent = packageManager.getLaunchIntentForPackage(packageNameTarget);
            startActivity(intent);
        } else {
            Toast.makeText(getApplicationContext(), "启动的 APP 未安装", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 判断本地已经安装好了指定的应用程序包
     *
     * @param packageNameTarget :App 包名
     * @return 已安装时返回 true,不存在时返回 false
     */
    private boolean appIsExist(String packageNameTarget) {
        PackageManager packageManager = getPackageManager();
        List<PackageInfo> packageInfoList = packageManager.getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES);
        for (PackageInfo packageInfo : packageInfoList) {
            String packageNameSource = packageInfo.packageName;
            if (packageNameSource.equals(packageNameTarget)) {
                return true;
            }
        }
        return false;
    }
}