本文导读
- 如果想要在 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 的简单理解:
- android.intent.action.MAIN:表明该 Activity 可以作为 APP 入口启动,一个 APP 可以有多个入口,例如微信的主界面(用户点击进入)和微信的支付界面(第三方调用进入)
- android.intent.category.LAUNCHER:表明该 Activity 可在桌面显示(点击APP图标就会触发此Activity)
调用操作
获取系统所有应用信息
- 需求分析:当手机上点击 "开始" 后,控制台输出右侧所示的信息,即手机中已经安装的所有 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 ——飞猪
启动第三方 APP
- 上面已经知道了如何获取手机中安装好的所有的应用的 包名,因为 Android 应用的包名必须在 Google 上唯一的,所以启动 第三方 APP 最简单方式就是根据它的 包名,核心代码如下:
PackageManager packageManager = getPackageManager(); Intent intent = packageManager.getLaunchIntentForPackage("被启动的包名"); startActivity(intent );
- 此种方式启动时,注意事项如下:
- 当调用的 APP(如下面的yuan)在最前端,被调用的第三方 APP 未启动时,则会被启动到最前端显示
- 当调用的 APP(如下面的yuan)在最前端,被调用的第三方 APP 已经在后台启动时,则会被切换到最前端显示
- 当调用的 APP(如下面的yuan)在后台运行,被调用的第三方 APP 未启动时,则会被启动到最前端显示
- 当调用的 APP(如下面的yuan)在后台运行,被调用的第三方 APP 也在后台运行时,则不会有任何效果
- 效果如下:当点击 "开始按钮"后,启动手机上的微博(包名com.sina.weibo),然后为了对比,启动一个不存在/未安装的 app,此时显示 "启动的 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;
}
}