我们一般代码调用安装apk会写下面的代码
Intent intent = new Intent(Intent.ACTION_VIEW); File apkFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/1.apk"); intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive"); startActivity(intent);
我们安装apk时系统会分析apk,然后弹出如下图的提示
当我们点击安装后,系统会进行安装
这里我们查看系统源码来看一下系统是怎么执行安装程序的
首先我们找到PackageInstallerActivity.java,一看命名规则就知道是apk安装的界面
既然是Activity 那么我们首先来看onCreate()方法
@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); //get intent information 获取Intent信息 final Intent intent = getIntent(); mPackageURI = intent.getData();//apk的uri mPm = getPackageManager(); mPkgInfo = PackageUtil.getPackageInfo(mPackageURI); // Check for parse errors 检查apk是否有错误 if(mPkgInfo == null) { Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); return; } //set view requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.install_start); //这就是上面的界面 mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, mPackageURI); PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); //check setting //是否设置了 允许安装未知来源,就是设置那里的 if(!isInstallingUnknownAppsAllowed()) { //ask user to enable setting first showDialogInner(DLG_UNKNOWN_APPS); return; } initiateInstall(); }
然后看initiateInstall()方法
private void initiateInstall() { String pkgName = mPkgInfo.packageName; // 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.setPackageName(pkgName); } // Check if package is already installed. display confirmation dialog if replacing pkg检查是否已经安装过了 try { mAppInfo = mPm.getApplicationInfo(pkgName, PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { mAppInfo = null; } if (mAppInfo == null) { startInstallConfirm();//安装 } else { if(localLOGV) Log.i(TAG, "Replacing existing package:"+ mPkgInfo.applicationInfo.packageName); showDialogInner(DLG_REPLACE_APP); } }
来到startInstallConfirm()
private void startInstallConfirm() { LinearLayout permsSection = (LinearLayout) mInstallConfirm.findViewById(R.id.permissions_section); LinearLayout securityList = (LinearLayout) permsSection.findViewById( R.id.security_settings_list); boolean permVisible = false; if(mPkgInfo != null) { AppSecurityPermissions asp = new AppSecurityPermissions(this, mPkgInfo); if(asp.getPermissionCount() > 0) { permVisible = true; securityList.addView(asp.getPermissionsView()); } } if(!permVisible){ permsSection.setVisibility(View.INVISIBLE); } mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); //确认按钮 mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); }
找点击事件 onClick()
public void onClick(View v) { if(v == mOk) { //开始安装,弹出安装进度界面 // Start subactivity to actually install the application Intent newIntent = new Intent(); newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo); newIntent.setData(mPackageURI); newIntent.setClass(this, InstallAppProgress.class); //这里调到了InstallAppProgress.java String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME); if (installerPackageName != null) { newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName); } if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); startActivity(newIntent); finish(); } else if(v == mCancel) { // Cancel and finish finish(); } }
继续跟踪 到InstallAppProgress.java 的onCreate()
@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); Intent intent = getIntent(); mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mPackageURI = intent.getData(); initView(); }
initView();
public void initView() { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.op_progress); int installFlags = 0; //设置錐lag PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); if(pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; //替换已经存在的 } } catch (NameNotFoundException e) { } if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { Log.w(TAG, "Replacing package:" + mAppInfo.packageName); } PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo, mPackageURI); mLabel = as.label; PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); mStatusTextView = (TextView)findViewById(R.id.center_text); mStatusTextView.setText(R.string.installing); mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); mProgressBar.setIndeterminate(true); // Hide button till progress is being displayed mOkPanel = (View)findViewById(R.id.buttons_panel); mDoneButton = (Button)findViewById(R.id.done_button); mLaunchButton = (Button)findViewById(R.id.launch_button); mOkPanel.setVisibility(View.INVISIBLE); String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME); PackageInstallObserver observer = new PackageInstallObserver(); pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);//安装的代码 }
几经周折,总算找到了。。。
下几句 关键的
int installFlags = 0; //设置Flag
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; //替换已经存在的
}
} catch (NameNotFoundException e) {
}
PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,
mPackageURI);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
PackageInstallObserver observer = new PackageInstallObserver();
pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);//安装的代
我们可以通过上面的代码直接进行安装,
不过我们需要android.Manifest.permission#INSTALL_PACKAGE,
此权限只有system应用才能使用.
所以此应用必须放入system/app下,
还有静默安装的一种方式是使用root权限 adb指令执行 install -r 进行安装