前言: 应公司发展需求,实现android app项目一键打包(即多个项目只需修改部分配置文件,实现一个android工程文件打包多个app项目)。首先需解决的问题就是项目资源替换问题,最终我们采用的是访问网页的形式避免压缩资源替换的复杂度(将app项目发布成网页,通过android壳进行访问,不同app只需替换访问地址即可);其次就是针对客户需求实现静默安装自启和开机自启功能。
一、环境配置 注:以下环境配置只针jdk1.8,若java环境不是该版本,其他环境需对应调整。 java:jdk1.8; android studio工具的gradle:4.1.3; 打包时的gradle:6.5; 本地gradle(命令行打包需要):6.5;
二、使用android studio新建空的android工程 新建android项目请自行百度,此处不再过多描述,工程建好后做以下简单那配置: 这里先预览一下目录结构: 新手注意,android studio打开工程时可以选择模式,通常使用Project和Android两种,两种打开的目录结构有差异,我常用Project模式。
首先要使用res目录下的activity_main.xml文件 activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="@+id/activity_main_webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
我们将通过WebView调用android设备的默认浏览器来访问网页(WebView也可指定浏览器,但不推荐,防止浏览器卸载)。
然后就需要在启动类的onCreate钩子中指定要打开的网页
MainActivity.java:
package com.ntc.app;
import ...
public class MainActivity extends Activity {
@Override
@SuppressLint("SetJavaScriptEnabled")
protected void onCreate(Bundle savedInstanceState) {
System.out.println("开始测试!!!!!!!!!!!!!!!!!!!");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
uniContext = MainActivity.this;
mWebView = findViewById(R.id.activity_main_webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.setWebViewClient(new MyWebViewClient());
mWebView.loadUrl("http://xxx.xxx/");
}
@Override
public void onBackPressed() {
if(mWebView.canGoBack()) {
mWebView.goBack();
} else {
super.onBackPressed();
}
}
}
WebViewClient.java:
```cpp
package com.ntc.app;
import android.content.Intent;
import android.net.Uri;
import android.webkit.WebView;
import android.webkit.WebViewClient;
class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
String hostname;
hostname = "example.com";
Uri uri = Uri.parse(url);
if (url.startsWith("file:") || uri.getHost() != null && uri.getHost().endsWith(hostname)) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
view.getContext().startActivity(intent);
return true;
}
}
到这里app启动就可以打开你指定的网页了。
三、配置开机自启
1、配置AndroidManifest.xml,添加权限(application同级节点)
<!-- 接收广播主要用于开机自启 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2、引入开机广播类(application节点下)
<receiver
android:name="com.ntc.app.PlayerReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<action android:name="android.intent.action.MEDIA_EJECT" />
<action android:name="android.intent.action.MEDIA_REMOVED" />
<data android:scheme="file" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
3、创建开机广播类 PlayerReceiver.java:
package com.ntc.app;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class PlayerReceiver extends BroadcastReceiver {
private final String ACTION_BOOT = "android.intent.action.BOOT_COMPLETED";
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Intent intentMainActivity = new Intent(context, MainActivity.class);
intentMainActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentMainActivity.setAction("android.intent.action.MAIN");
intentMainActivity.addCategory("android.intent.category.LAUNCHER");
context.startActivity(intentMainActivity);
}
}
}
四、检测当前版本与网络版本并对比更新 1、创建APKVersionCodeUtils类检测当前版本信息 APKVersionCodeUtils.java:
package com.ntc.app;
import android.content.Context;
import android.content.pm.PackageManager;
public class APKVersionCodeUtils {
public static int getVersionCode(Context uniContext) {
int versionCode = 0;
try {
versionCode = uniContext.getPackageManager().
getPackageInfo(uniContext.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return versionCode;
}
public static String getVerName(Context context) {
String verName = "";
try {
verName = context.getPackageManager().
getPackageInfo(context.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return verName;
}
}
2、创建CheckUpdates类检测网络版本信息 注:在检测网络版本信息时,我是在服务器上准备了一个json文件供测试项目请求并将高版本的安装包放在服务器上供下载
update.json:
CheckUpdates.java:
package com.ntc.app;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class CheckUpdates {
Map<String, String> check(String URL) {
Map<String, String> map = new HashMap<String,String>();
String ApkUrl = "";
String Version = "";
String apkName = "";
try {
URL url = new URL(URL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
InputStreamReader is = new InputStreamReader(conn.getInputStream());
BufferedReader bufferedReader = new BufferedReader(is);
StringBuffer strBuffer = new StringBuffer();
String line = null;
while (null!=(line = bufferedReader.readLine())) {
strBuffer.append(line);
}
String objectStr = strBuffer.toString();
JSONObject jsonObject = JSONObject.parseObject(objectStr);
ApkUrl = (String) jsonObject.get("url");
Version = jsonObject.get("version").toString();
apkName = (String) jsonObject.get("apkName");
map.put("ApkUrl", ApkUrl);
map.put("version", Version);
map.put("apkName", apkName);
is.close();
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
3、配置AndroidManifest.xml
<!-- sd卡内创建和删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" tools:ignore="ProtectedPermissions" />
<!-- 允许程序向外部存储设备写数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
...>
...
<!-- 获取文件读取权限 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.ntc.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"
/>
</provider>
</application>
4、在res目录下创建xml/filepaths.xml文件 filepaths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external" path="."/>
</paths>
6、在MainActivity 主类中定时循环检测 MainActivity.java完整代码:
package com.ntc.app;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.webkit.WebSettings;
import android.webkit.WebView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import uni.fvv.packageManager.util.PackageUtils;
public class MainActivity extends Activity {
private WebView mWebView;
private Context uniContext;
private Timer timer;
private TimerTask timerTask;
private boolean mIsCancel = false;
private int mProgress;
private String mSavePath;
private String newApk_name="";
private String ApkUrl ="";
@Override
@SuppressLint("SetJavaScriptEnabled")
protected void onCreate(Bundle savedInstanceState) {
System.out.println("开始测试!!!!!!!!!!!!!!!!!!!");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
uniContext = MainActivity.this;
mWebView = findViewById(R.id.activity_main_webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.setWebViewClient(new MyWebViewClient());
mWebView.loadUrl("https://www.baidu.com/");
final String versionName = APKVersionCodeUtils.getVerName(this);
final int versionCode = APKVersionCodeUtils.getVersionCode(this);
String apk = getExternalFilesDir(null) + "/";
File apkDir = new File(apk+"apk");
if (apkDir.exists()){
apkDir.delete();
}
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("!!!!!!!!!!!!!!!!!!!!定时器执行,请让陆!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
CheckUpdates CheckUpdates = new CheckUpdates();
Map newVersionInfo = CheckUpdates.check("http://xx.xxx.xx.x:2021/update.json");
Integer newVersionCode = Integer.parseInt(newVersionInfo.get("version").toString());
newApk_name = (String) newVersionInfo.get("apkName");
ApkUrl = (String) newVersionInfo.get("ApkUrl");
System.out.println(versionName+"!!222222222222222!!"+newVersionCode);
if(newVersionCode>versionCode){
downloadAPK();
}else {
}
}
};
timer.schedule(timerTask, 1000, 600000);
}
@Override
public void onBackPressed() {
if(mWebView.canGoBack()) {
mWebView.goBack();
} else {
super.onBackPressed();
}
}
private void downloadAPK() {
new Thread(new Runnable() {
@Override
public void run() {
try{
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
String sdPath = getExternalFilesDir(null) + "/";
System.out.println(sdPath+"!!!!!!!!");
mSavePath = sdPath + "apk";
File dir = new File(mSavePath);
if (!dir.exists()){
dir.mkdir();
}
HttpURLConnection conn = (HttpURLConnection) new URL(ApkUrl).openConnection();
conn.connect();
InputStream is = conn.getInputStream();
int length = conn.getContentLength();
File apkFile = new File(mSavePath, newApk_name);
FileOutputStream fos = new FileOutputStream(apkFile);
int count = 0;
byte[] buffer = new byte[1024];
while (!mIsCancel){
int numread = is.read(buffer);
count += numread;
mProgress = (int) (((float)count/length) * 100);
if (numread < 0){
System.out.println("!!!! 下载完成 !!!!");
int as = PackageUtils.install(MainActivity.this, mSavePath+"/"+newApk_name);
break;
}
fos.write(buffer, 0, numread);
}
fos.close();
is.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
}
}
5、新建安装方法包PackageUtils.install(install方法可网上百度)并添加更新重启依赖模块 packagemanager-release.aar(可网上下载)
将packagemanager-release.aar包放入libs文件下
PackageUtils.java:
package uni.fvv.packageManager.util;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.Build.VERSION;
import android.util.Base64;
import android.util.Log;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import uni.fvv.packageManager.util.ShellUtils.CommandResult;
public class PackageUtils {
public static final String TAG = "PackageUtils";
public static final int APP_INSTALL_AUTO = 0;
public static final int APP_INSTALL_INTERNAL = 1;
public static final int APP_INSTALL_EXTERNAL = 2;
public static final int INSTALL_SUCCEEDED = 1;
public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
public static final int INSTALL_FAILED_INVALID_APK = -2;
public static final int INSTALL_FAILED_INVALID_URI = -3;
public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
public static final int INSTALL_FAILED_DEXOPT = -11;
public static final int INSTALL_FAILED_OLDER_SDK = -12;
public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
public static final int INSTALL_FAILED_NEWER_SDK = -14;
public static final int INSTALL_FAILED_TEST_ONLY = -15;
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
public static final int INSTALL_FAILED_UID_CHANGED = -24;
public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
public static final int INSTALL_FAILED_OTHER = -1000000;
public static final int DELETE_SUCCEEDED = 1;
public static final int DELETE_FAILED_INTERNAL_ERROR = -1;
public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;
public static final int DELETE_FAILED_INVALID_PACKAGE = -3;
public static final int DELETE_FAILED_PERMISSION_DENIED = -4;
private PackageUtils() {
throw new AssertionError();
}
public static final int install(Context context, String filePath) {
if (!isSystemApplication(context) && !uni.fvv.packageManager.util.ShellUtils.checkRootPermission()) {
return installNormal(context, filePath) ? 1 : -3;
} else {
return installSilent(context, filePath);
}
}
@SuppressLint("WrongConstant")
public static boolean installNormal(Context context, String filePath) {
Intent i = new Intent("android.intent.action.VIEW");
File file = new File(filePath);
if (file != null && file.exists() && file.isFile() && file.length() > 0L) {
i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
i.addFlags(268435456);
context.startActivity(i);
return true;
} else {
return false;
}
}
public static int installSilent(Context context, String filePath) {
return installSilent(context, filePath, " -r " + getInstallLocationParams());
}
public static int installSilent(Context context, String filePath, String pmParams) {
if (filePath != null && filePath.length() != 0) {
File file = new File(filePath);
if (file != null && file.length() > 0L && file.exists() && file.isFile()) {
StringBuilder command = (new StringBuilder()).append("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install ").append(pmParams == null ? "" : pmParams).append(" ").append(filePath.replace(" ", "\\ "));
CommandResult commandResult = uni.fvv.packageManager.util.ShellUtils.execCommand(command.toString(), !isSystemApplication(context), true);
if (commandResult.successMsg == null || !commandResult.successMsg.contains("Success") && !commandResult.successMsg.contains("success")) {
Log.e("PackageUtils", "installSilent successMsg:" + commandResult.successMsg + ", ErrorMsg:" + commandResult.errorMsg);
if (commandResult.errorMsg == null) {
return -1000000;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_ALREADY_EXISTS")) {
return -1;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_APK")) {
return -2;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_URI")) {
return -3;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_INSUFFICIENT_STORAGE")) {
return -4;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_DUPLICATE_PACKAGE")) {
return -5;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_NO_SHARED_USER")) {
return -6;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_UPDATE_INCOMPATIBLE")) {
return -7;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE")) {
return -8;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_MISSING_SHARED_LIBRARY")) {
return -9;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_REPLACE_COULDNT_DELETE")) {
return -10;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_DEXOPT")) {
return -11;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_OLDER_SDK")) {
return -12;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_CONFLICTING_PROVIDER")) {
return -13;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_NEWER_SDK")) {
return -14;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_TEST_ONLY")) {
return -15;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE")) {
return -16;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_MISSING_FEATURE")) {
return -17;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_CONTAINER_ERROR")) {
return -18;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_INSTALL_LOCATION")) {
return -19;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_MEDIA_UNAVAILABLE")) {
return -20;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_VERIFICATION_TIMEOUT")) {
return -21;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_VERIFICATION_FAILURE")) {
return -22;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_PACKAGE_CHANGED")) {
return -23;
} else if (commandResult.errorMsg.contains("INSTALL_FAILED_UID_CHANGED")) {
return -24;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_NOT_APK")) {
return -100;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_MANIFEST")) {
return -101;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION")) {
return -102;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_NO_CERTIFICATES")) {
return -103;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES")) {
return -104;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING")) {
return -105;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME")) {
return -106;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID")) {
return -107;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED")) {
return -108;
} else if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_MANIFEST_EMPTY")) {
return -109;
} else {
return commandResult.errorMsg.contains("INSTALL_FAILED_INTERNAL_ERROR") ? -110 : -1000000;
}
} else {
return 1;
}
} else {
return -3;
}
} else {
return -3;
}
}
public static final int uninstall(Context context, String packageName) {
if (!isSystemApplication(context) && !uni.fvv.packageManager.util.ShellUtils.checkRootPermission()) {
return uninstallNormal(context, packageName) ? 1 : -3;
} else {
return uninstallSilent(context, packageName);
}
}
@SuppressLint("WrongConstant")
public static boolean uninstallNormal(Context context, String packageName) {
if (packageName != null && packageName.length() != 0) {
Intent i = new Intent("android.intent.action.DELETE", Uri.parse((new StringBuilder(32)).append("package:").append(packageName).toString()));
i.addFlags(268435456);
context.startActivity(i);
return true;
} else {
return false;
}
}
public static int uninstallSilent(Context context, String packageName) {
return uninstallSilent(context, packageName, true);
}
public static int uninstallSilent(Context context, String packageName, boolean isKeepData) {
if (packageName != null && packageName.length() != 0) {
StringBuilder command = (new StringBuilder()).append("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall").append(isKeepData ? " -k " : " ").append(packageName.replace(" ", "\\ "));
CommandResult commandResult = uni.fvv.packageManager.util.ShellUtils.execCommand(command.toString(), !isSystemApplication(context), true);
if (commandResult.successMsg != null && (commandResult.successMsg.contains("Success") || commandResult.successMsg.contains("success"))) {
return 1;
} else {
Log.e("PackageUtils", "uninstallSilent successMsg:" + commandResult.successMsg + ", ErrorMsg:" + commandResult.errorMsg);
if (commandResult.errorMsg == null) {
return -1;
} else {
return commandResult.errorMsg.contains("Permission denied") ? -4 : -1;
}
}
} else {
return -3;
}
}
public static boolean isSystemApplication(Context context) {
return context == null ? false : isSystemApplication(context, context.getPackageName());
}
public static boolean isSystemApplication(Context context, String packageName) {
return context == null ? false : isSystemApplication(context.getPackageManager(), packageName);
}
public static boolean isSystemApplication(PackageManager packageManager, String packageName) {
if (packageManager != null && packageName != null && packageName.length() != 0) {
try {
ApplicationInfo app = packageManager.getApplicationInfo(packageName, 0);
return app != null && (app.flags & 1) > 0;
} catch (NameNotFoundException var3) {
var3.printStackTrace();
return false;
}
} else {
return false;
}
}
public static Boolean isTopActivity(Context context, String packageName) {
if (context != null && !uni.fvv.packageManager.util.StringUtils.isEmpty(packageName)) {
ActivityManager activityManager = (ActivityManager)context.getSystemService("activity");
List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(1);
if (ListUtils.isEmpty(tasksInfo)) {
return null;
} else {
try {
return packageName.equals(((RunningTaskInfo)tasksInfo.get(0)).topActivity.getPackageName());
} catch (Exception var5) {
var5.printStackTrace();
return false;
}
}
} else {
return null;
}
}
public static String getTopPackageName(Context context) {
if (context == null) {
return null;
} else {
ActivityManager activityManager = (ActivityManager)context.getSystemService("activity");
List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(1);
if (ListUtils.isEmpty(tasksInfo)) {
return null;
} else {
try {
return ((RunningTaskInfo)tasksInfo.get(0)).topActivity.getPackageName();
} catch (Exception var4) {
return null;
}
}
}
}
public static boolean isRunning(Context context, String packageName) {
ActivityManager am = (ActivityManager)context.getSystemService("activity");
List<RunningAppProcessInfo> infos = am.getRunningAppProcesses();
Iterator var4 = infos.iterator();
RunningAppProcessInfo rapi;
do {
if (!var4.hasNext()) {
return false;
}
rapi = (RunningAppProcessInfo)var4.next();
} while(!rapi.processName.equals(packageName));
return true;
}
public static boolean checkPackageInstall(Context context, String packageName) {
PackageInfo packageInfo = null;
try {
packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
} catch (NameNotFoundException var4) {
var4.printStackTrace();
}
return packageInfo != null;
}
@SuppressLint("WrongConstant")
public static void openApp(Context context, String packageName, JSONObject extra) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if (packageName.contains(":")) {
intent = new Intent();
intent.setData(Uri.parse(packageName));
}
if (intent != null) {
if (extra != null) {
Iterator var4 = extra.keySet().iterator();
while(var4.hasNext()) {
String item = (String)var4.next();
Log.i(item, extra.getString(item));
intent.putExtra(item, extra.getString(item));
}
}
intent.setFlags(268435456);
context.startActivity(intent);
}
}
public static JSONArray getAppList(Context context) {
PackageManager packageManager = context.getPackageManager();
Intent mainIntent = new Intent("android.intent.action.MAIN", (Uri)null);
mainIntent.addCategory("android.intent.category.LAUNCHER");
JSONArray jsonArray = new JSONArray();
List<PackageInfo> apps = packageManager.getInstalledPackages(0);
for(int i = 0; i < apps.size(); ++i) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("packageName", ((PackageInfo)apps.get(i)).packageName);
jsonObject.put("appName", ((PackageInfo)apps.get(i)).applicationInfo.loadLabel(packageManager).toString());
jsonObject.put("version", ((PackageInfo)apps.get(i)).versionName);
boolean isSystem = false;
if ((1 & ((PackageInfo)apps.get(i)).applicationInfo.flags) != 0) {
isSystem = true;
}
jsonObject.put("isSystem", isSystem);
jsonArray.add(jsonObject);
}
return jsonArray;
}
private static String bitmap2base64(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, baos);
byte[] bytes = baos.toByteArray();
return Base64.encodeToString(bytes, 0);
}
public static int getAppVersionCode(Context context) {
if (context != null) {
PackageManager pm = context.getPackageManager();
if (pm != null) {
try {
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
if (pi != null) {
return pi.versionCode;
}
} catch (NameNotFoundException var4) {
var4.printStackTrace();
}
}
}
return -1;
}
public static int getInstallLocation() {
CommandResult commandResult = uni.fvv.packageManager.util.ShellUtils.execCommand("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm get-install-location", false, true);
if (commandResult.result == 0 && commandResult.successMsg != null && commandResult.successMsg.length() > 0) {
try {
int location = Integer.parseInt(commandResult.successMsg.substring(0, 1));
switch(location) {
case 1:
return 1;
case 2:
return 2;
}
} catch (NumberFormatException var2) {
var2.printStackTrace();
Log.e("PackageUtils", "pm get-install-location error");
}
}
return 0;
}
private static String getInstallLocationParams() {
int location = getInstallLocation();
switch(location) {
case 1:
return "-f";
case 2:
return "-s";
default:
return "";
}
}
@SuppressLint("WrongConstant")
public static void startInstalledAppDetails(Context context, String packageName) {
Intent intent = new Intent();
int sdkVersion = VERSION.SDK_INT;
if (VERSION.SDK_INT >= 9) {
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", packageName, (String)null));
} else {
intent.setAction("android.intent.action.VIEW");
intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
intent.putExtra(sdkVersion == 8 ? "pkg" : "com.android.settings.ApplicationPkgName", packageName);
}
intent.addFlags(268435456);
context.startActivity(intent);
}
}
本着代码完整性,特在此放上AndroidManifest.xml、build.gradle的完整代码以作记录(防止我忘记了) AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.ntc.app"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- sd卡内创建和删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" tools:ignore="ProtectedPermissions" />
<!-- 允许程序向外部存储设备写数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 接收广播主要用于开机自启 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="@mipmap/icon"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:configChanges="orientation|screenSize"
android:name="com.ntc.app.MainActivity"
android:label="@string/app_name"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.ntc.app.PlayerReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<action android:name="android.intent.action.MEDIA_EJECT" />
<action android:name="android.intent.action.MEDIA_REMOVED" />
<data android:scheme="file" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<!-- 获取文件读取权限 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.ntc.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"
/>
</provider>
<!-- <receiver android:name="uni.fvv.packageManager.ReplaceAddRemoveBroadcastReceiver" >-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.PACKAGE_REPLACED" />-->
<!-- <data android:scheme="package" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
</application>
</manifest>
build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.ntc2.app"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
aaptOptions {
additionalParameters '--auto-add-overlay'
ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"
}
android.applicationVariants.all {
variant ->
variant.outputs.all {
outputFileName = "webtest-v${variant.versionName}.apk"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
implementation "com.android.support:support-v4:28.0.0"
implementation "com.android.support:appcompat-v7:28.0.0"
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.facebook.fresco:fresco:1.13.0'
implementation "com.facebook.fresco:animated-gif:1.13.0"
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.alibaba:fastjson:1.1.46.android'
implementation 'org.apache.commons:commons-io:1.3.2'
}
至此就可使用android studio打包了 弹药实现一键打包就必须使用命令行打包: cd至工程目录: 执行命令
gradle clean
gradle assembleDebug
更多打包命令可自行百度
|