学习记录一下,开源是一种精神,也是一种浪漫
前置条件:需要手机root,不root很头疼,sdk32,jdk1.8都能自己任选
前置:实现思路:
①:通过root权限,使用"su"和pm install -r用以静默安装,然后通过广播监听静默安装成功后重启此程序
②:需要将程序打包成apk文件,最好是打包成release,注:直接AS运行的程序,在里面点击安装需要更新的新版本的apk是会显示无法安装成功的
打包apk借鉴:
Android Studio 打包APK(详细版)_as打包apk-CSDN博客
③:要注意的点是:第n次的版本需要需要比第n-1次高,只需要修改如下图的
android:value="1.0.0.1"-->android:value="1.0.0.2"就好,build.gradle也要一起变。
需要在清单文件(AndroidManifest.xml)和build.gradle文件加上:
1、静默安装实现类:
public class SilentInstall {
/**
* 执行具体的静默安装逻辑,需要手机ROOT。
* @param apkPath
* 要安装的apk文件的路径
* @return 安装成功返回true,安装失败返回false。
*/
public boolean install(String apkPath) {
boolean result = false;
DataOutputStream dataOutputStream = null;
BufferedReader errorStream = null;
try {
// 申请su权限
Process process = Runtime.getRuntime().exec("su");
dataOutputStream = new DataOutputStream(process.getOutputStream());
// 执行pm install命令
String command = "pm install -r " + apkPath + "\n";
dataOutputStream.write(command.getBytes(Charset.forName("utf-8")));
dataOutputStream.flush();
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
process.waitFor();
errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String msg = "";
String line;
// 读取命令的执行结果
while ((line = errorStream.readLine()) != null) {
msg += line;
}
Log.d("TAG", "install msg is " + msg);
// 如果执行结果中包含Failure字样就认为是安装失败,否则就认为安装成功
if (!msg.contains("Failure")) {
result = true;
}
} catch (Exception e) {
Log.e("TAG", e.getMessage(), e);
} finally {
try {
if (dataOutputStream != null) {
dataOutputStream.close();
}
if (errorStream != null) {
errorStream.close();
}
} catch (IOException e) {
Log.e("TAG", e.getMessage(), e);
}
}
return result;
}
}
2、MainActivity
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
verifyStoragePermissions(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SilentInstall installHelper = new SilentInstall();
//这块我写死了,具体你们可以看着写
installHelper.install("/storage/emulated/0/helll.apk");
}
});
}
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the u
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE);
}
}
}
3、监听静默安装成功后的挂广播,UpdateReceiver,需要在清单文件注册广播
public class UpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 检查广播的类型
if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) {
// 启动应用的主活动
Intent launchIntent = new Intent(context, MainActivity.class);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(launchIntent);
// 显示 Toast 消息
Toast.makeText(context, "已启动", Toast.LENGTH_LONG).show();
}
}
}
4、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="我很好"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="115dp"
tools:layout_editor_absoluteY="286dp" />
</android.support.constraint.ConstraintLayout>
5、清单文件:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ttt.helll">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.InstallTest2">
<receiver android:name=".UpdateReceiver">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="26" android:targetSdkVersion="32"/>
<meta-data android:name="android.versionCode" android:value="1"/>
<meta-data android:name="android.versionName" android:value="1.0.0.1"/>
</manifest>
6、build.gradle
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 32
defaultConfig {
applicationId "com.ttt.helll"
minSdkVersion 26
targetSdkVersion 32
versionCode 1
versionName "1.0.0.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
完结,撒花❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀,一起加油