前段时间我记得沙滩有人问这个问题,问题即下图 当时我给的解决办法是在vendor\mediatek\proprietary\packages\apps\SettingsProvider\res\values\defaults.xml中把这个def_install_non_market_apps字符串改为true,但是这个方法是在安卓十一上可以用,但是不一定一定就可以用,还有一种方法是直接给予权限,方法如下: 先在AppOpsManager.java中把安装权限改为允许
--- a/frameworks/base/core/java/android/app/AppOpsManager.java
+++ b/frameworks/base/core/java/android/app/AppOpsManager.java
@@ -2254,9 +2254,9 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED, // RUN_IN_BACKGROUND
AppOpsManager.MODE_ALLOWED, // AUDIO_ACCESSIBILITY_VOLUME
AppOpsManager.MODE_ALLOWED, // READ_PHONE_NUMBERS
- AppOpsManager.MODE_DEFAULT, // REQUEST_INSTALL_PACKAGES
+ AppOpsManager.MODE_ALLOWED, // REQUEST_INSTALL_PACKAGES
AppOpsManager.MODE_ALLOWED, // PICTURE_IN_PICTURE
- AppOpsManager.MODE_DEFAULT, // INSTANT_APP_START_FOREGROUND
+ AppOpsManager.MODE_ALLOWED, // INSTANT_APP_START_FOREGROUND
AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
AppOpsManager.MODE_ALLOWED, // RUN_ANY_IN_BACKGROUND
AppOpsManager.MODE_ALLOWED, // CHANGE_WIFI_STATE
@@ -7451,7 +7451,8 @@ public class AppOpsManager {
+ "#noteOpNoThrow(java.lang.String, int, java.lang.String, java.lang.String, "
+ "java.lang.String)} instead")
public int noteOpNoThrow(int op, int uid, String packageName) {
- return noteOpNoThrow(op, uid, packageName, null, null);
+ // return noteOpNoThrow(op, uid, packageName, null, null);
+ return AppOpsManager.MODE_ALLOWED;
}
/**
然后把检测权限的方法改为true即可
diff --git a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java
old mode 100644
new mode 100755
index fe1d81c..131cdbb
--- a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java
+++ b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java
@@ -75,7 +75,8 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
getIntent().getComponent().getClassName())) {
setResult(checked ? RESULT_OK : RESULT_CANCELED);
}
- setCanInstallApps(checked);
+ // setCanInstallApps(checked);
+ setCanInstallApps(true);
refreshUi();
}
return true;
@@ -127,9 +128,9 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
}
if (mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserHandle.of(UserHandle.myUserId()))) {
- mSwitchPref.setChecked(false);
+ mSwitchPref.setChecked(true);
mSwitchPref.setSummary(R.string.disabled);
- mSwitchPref.setEnabled(false);
+ mSwitchPref.setEnabled(true);
return true;
}
mSwitchPref.checkRestrictionAndSetDisabled(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
@@ -144,10 +145,10 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
mPackageInfo.applicationInfo.uid);
if (!mInstallAppsState.isPotentialAppSource()) {
// Invalid app entry. Should not allow changing permission
- mSwitchPref.setEnabled(false);
+ mSwitchPref.setEnabled(true);
return true;
}
- mSwitchPref.setChecked(mInstallAppsState.canInstallApps());
+ mSwitchPref.setChecked(true);
return true;
}
但是这种方法在安卓十三上不可以了,这样改虽然在设置中允许来自此来源的应用的开关看着是打开了,但是实际上还是没有给到权限,还是有弹窗,我想到了一个办法可以绕过这个权限,屏蔽那个弹窗直接安装apk就行了,下面看解决办法
diff --git a/alps_mssi/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/alps_mssi/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
old mode 100644
new mode 100755
index 9c6113ce4b4..4386f28ee49
--- a/alps_mssi/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/alps_mssi/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -262,6 +262,7 @@ public class PackageInstallerActivity extends AlertActivity {
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
+ Log.d("swl","pkgName: "+pkgName);
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
@@ -524,7 +525,9 @@ public class PackageInstallerActivity extends AlertActivity {
mOriginatingPackage, AppOpsManager.MODE_ERRORED);
// fall through
case AppOpsManager.MODE_ERRORED:
- showDialogInner(DLG_EXTERNAL_SOURCE_BLOCKED);
+ //showDialogInner(DLG_EXTERNAL_SOURCE_BLOCKED);
+ Log.d("swl","AppOpsManager.MODE_ERRORED: " +AppOpsManager.MODE_ERRORED);
+ initiateInstall();
break;
case AppOpsManager.MODE_ALLOWED:
initiateInstall();
在系统中,apk的安装是通过PackageInstallerActivity来进行的,这个类会显示一个安装界面,显示apk的名称、图标、权限等信息,并提供安装按钮供用户点击,还会检查设备上的存储空间是否足够,并在安装过程中显示进度条和安装结果,以及检测apk安装来源,在系统中显示未知来源弹窗的方法为showDialogInner,源码如下:
/**
* Replace any dialog shown by the dialog with the one for the given {@link #createDialog id}.
*
* @param id The dialog type to add
*/
private void showDialogInner(int id) {
if (mLocalLOGV) Log.i(TAG, "showDialogInner(" + id + ")");
DialogFragment currentDialog =
(DialogFragment) getFragmentManager().findFragmentByTag("dialog");
Log.d("swl","111");
if (currentDialog != null) {
currentDialog.dismissAllowingStateLoss();
Log.d("swl","222");
}
DialogFragment newDialog = createDialog(id);
if (newDialog != null) {
Log.d("swl","333");
newDialog.;
}
}
在加了log以后知道了每次弹未知来源弹窗的时候都会走1和3,它是通过getFragmentManager().findFragmentByTag("dialog")来获取当前正在显示的对话框,如果当前有调用dismissAllowingStateLoss()方法结束对话框,然后创键一个弹窗,再通过showAllowingStateLoss(getFragmentManager(), "dialog")来显示弹框,知道这个弹窗是干嘛的以后直接在这个类中加log,通过log知道了在位置来源弹窗弹出来的时候也会走下面这里:
switch (appOpMode) {
case AppOpsManager.MODE_DEFAULT:
mAppOpsManager.setMode(appOpCode, mOriginatingUid,
mOriginatingPackage, AppOpsManager.MODE_ERRORED);
// fall through
case AppOpsManager.MODE_ERRORED:
//showDialogInner(DLG_EXTERNAL_SOURCE_BLOCKED);
Log.d("swl","AppOpsManager.MODE_ERRORED: " +AppOpsManager.MODE_ERRORED);
initiateInstall();
break;
case AppOpsManager.MODE_ALLOWED:
initiateInstall();
break;
default:
Log.e(TAG, "Invalid app op mode " + appOpMode
+ " for OP_REQUEST_INSTALL_PACKAGES found for uid " + mOriginatingUid);
finish();
break;
}
找到弹框并去掉再加上默认直接安装apk就可以实现了需求,在系统中安装apk都会调用initiateInstall()方法,不管是浏览器下载的还是应用商店下载的,用adb install除外,源码如下:
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
Log.d("swl","pkgName: "+pkgName);
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.MATCH_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
startInstallConfirm();
}
昨天老舅说可不可以实现只装自己公司的apk,别的apk禁止安装,这当然可以实现,在这个方法中加个包名过滤就可以了,有一说一在系统开发一定要多用log,方便很多,源码不一定全部都要读懂,尤其是我现在做的整个系统的,framework、package、vendor、kernel都有涉及,东西太多了绝对没人都懂这些源码,用的时候可以快速找到并解决客户需求就可以了。写起来弹窗还有一个弹窗也可以去掉,低版本apk安装到高版本系统中启动apk会弹出应用版本过低提示框,这个弹框在AppWarnings.java中,源码如下:
/**
* Shows the "deprecated target sdk" warning, if necessary.
*
* @param r activity record for which the warning may be displayed
*/
public void showDeprecatedTargetDialogIfNeeded(ActivityRecord r) {
if (r.info.applicationInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
mUiHandler.showDeprecatedTargetDialog(r);
}
}
/**
* Called when an activity is being started.
*
* @param r record for the activity being started
*/
public void onStartActivity(ActivityRecord r) {
showUnsupportedCompileSdkDialogIfNeeded(r);
showUnsupportedDisplaySizeDialogIfNeeded(r);
//showDeprecatedTargetDialogIfNeeded(r);
}
在低版本apk启动之前会调用showDeprecatedTargetDialogIfNeeded(r)方法去检测apk的SDK版本,如果低于Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT就会弹出弹窗,解决办法直接就是直接把这个检测方法去掉就行了,还有一篇文章写下拉菜单添加截屏(原生系统是没有截屏的)的功能,一篇写怎么在安兔兔还有设置中做假设备的参数信息的,这些有时间再写,毕竟打工人摸鱼才是主业!