Android silent installation Implementation Imitation 360 mobile phone assistant Second Pack and intelligent installation function _android

Source: Internet
Author: User
Tags flush getmessage pack xmlns

I've had a lot of friends ask me, how can I install a silent installation in the Android system? The so-called silent installation, is not to eject the system installation interface, without affecting the user any operation of the circumstances unknowingly installed the program. Although this approach does not seem to disturb the user, but there is a problem, because the Android system in the installation interface to show the permissions that the program is declared to the user, the user to evaluate these permissions and then decide whether to install the program, but if the use of silent installation method, There is no place for users to see permissions, the equivalent of the user passively accepted these permissions. In the view of the Android authorities, this display is a very dangerous behavior, so the silent installation of this behavior system is not open to developers.

But always popping up a setup dialog box is really a less experienced behavior, which Google itself realizes, so the Android system opens up silent installation permissions for its Google Play store, which means all from Google Play download-and-download applications are not allowed to eject the installation dialog box. This is a good indication of the importance of having authority, how to change the system of your own. For reference to Google's approach, many domestic mobile phone manufacturers have adopted a similar approach, such as millet mobile phone in the Millet store download application is not required to eject the installation dialog box, because the millet can be in the MIUI of the Android system for a variety of customization. Therefore, if we just do a common application, it is not really necessary to consider the silent installation of this feature, because we only need to put the application into the corresponding store, will automatically have a silent installation function.

But what if we want to do a store-like platform? For example, like 360 mobile phone assistants, it is widely installed in a variety of mobile phones, but as a common application exists, and no Google or millet such special permissions, the 360 mobile phone assistants should be how to do a better installation experience it? For this 360 mobile phone assistants provide two options, seconds installed (need root permissions) and intelligent installation, as shown below:

Therefore, today we will imitate the 360 Mobile phone helper implementation, to provide you with a set of silent installation solutions.

One, second pack

The so-called second is actually need root permissions of the silent installation, in fact, the principle of silent installation is very simple, that is, call the Android system pm Install command can be, but the key problem is that the PM command system is not granted us permission to call, So you can only apply for permission on a mobile phone that has root privileges.

Let's start by creating a new Installtest project, and then create a Silentinstall class as the implementation class for the silent install function, as shown in the following code:

/** * Silently installs the implementation class, calls the install () method to perform the specific silent installation logic. * Original address: http://blog.csdn.net/guolin_blog/article/details/47803149 * @author Guolin * @since 2015/12/7/Public Clas 
 s Silentinstall {/** * Performs a specific silent installation logic that requires cell phone root. 
 * @param Apkpath * The path of the APK file to be installed @return Successful installation returns True, and the installation failure returns false. 
 */Public Boolean install (String Apkpath) {Boolean result = false; 
 DataOutputStream dataoutputstream = null; 
 BufferedReader errorstream = null; 
  try {//Request SU permission process process = Runtime.getruntime (). EXEC ("su"); 
  DataOutputStream = new DataOutputStream (Process.getoutputstream ()); 
  Execute pm Install 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; Read the execution result of the command 
  while (line = Errorstream.readline ())!= null) {msg + line; 
  } log.d ("TAG", "Install msg is" + msg); 
  If the execution result contains the failure typeface, it is considered an installation failure, otherwise the installation succeeds if (!msg.contains ("failure")) {results = true; 
 The catch (Exception e) {log.e ("TAG", E.getmessage (), E); 
  Finally {try {if (DataOutputStream!= null) {dataoutputstream.close (); 
  } if (Errorstream!= null) {errorstream.close (); 
  The catch (IOException e) {log.e ("TAG", E.getmessage (), E); 
 } return result; 
 } 
 
}

As you can see, there is only one install () method in the Silentinstall class, and all of the silent installation logic is in this method, so let's look at this method specifically. The Runtime.getruntime (). EXEC ("su") method is invoked first in line 21st, where the root permission is first requested, otherwise the subsequent operation will fail. Then start assembling the silent installation command on line 24th, the format of the command is the PM install-r <apk Path >,-r parameter means that if the APK to be installed already exists, the APK path is passed as a method parameter. The next few lines are the process of executing the above command, and note that the installation process is synchronized, so we call the Process.waitfor () method below, that is, how long we will be waiting here. After waiting for the end of the installation process, we are going to read the results of the installation and parsing, the logic of parsing is also very simple, if the installation results include failure words to explain the installation failed, otherwise the installation was successful.

The whole approach is pretty straightforward, so let's build an environment that calls this method. Modify the code in the Activity_main.xml as follows:

<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout 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" android:orientation= "vertical" android:paddingbottom= "@dimen/activity_vertical_margin" Android: paddingleft= "@dimen/activity_horizontal_margin" android:paddingright= "@dimen/activity_horizontal_margin" Android :p addingtop= "@dimen/activity_vertical_margin" tools:context= "com.example.installtest.MainActivity" > < LinearLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" > <Button android:la Yout_width= "Wrap_content" android:layout_height= "wrap_content" android:onclick= "Onchooseapkfile" android:text= "selection Install package "/> <textview android:id=" @+id/apkpathtext "android:layout_width=" 0DP "android:layout_height=" Wrap_ Content "android:layout_weight=" 1 "android:layout_gravity= "center_vertical"/> </LinearLayout> <view android:layout_width= "Match_parent" Andro id:layout_height= "1DP" android:background= "@android: Color/darker_gray"/> <button android:layout_width= "wrap _content "android:layout_height=" wrap_content "android:onclick=" Onsilentinstall "android:text=" second outfit "/> <Vie W android:layout_width= "Match_parent" android:layout_height= "1DP" android:background= "@android: Color/darker_gray" /> <button android:layout_width= "wrap_content android:layout_height=" wrap_content "android:onClick=" OnFor Wardtoaccessibility "android:text=" open intelligent Installation Services/> <button android:layout_width= "Wrap_content" android:layout 
 _height= "Wrap_content" android:onclick= "Onsmartinstall" android:text= "Smart Installation"/> </LinearLayout>

Here we will first determine the main interface of the program, the main interface has four buttons, the first button to select the APK file, the second button for the start of the second, the third button to open the Intelligent installation Service, the fourth button to start intelligent installation, where we can only use the first two buttons. Then the install () method that calls Silentinstall needs to be passed into APK road
, so we need to first make the function of the file selector, new Activity_file_explorer.xml and List_item.xml as the file selector layout file, the code is as follows:

<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout xmlns:android= 
"http://schemas.android.com/apk/" Res/android " 
android:orientation=" vertical " 
android:layout_width=" match_parent " 
android:layout_" height= "Match_parent" > 

<listview 
android:id= "@+id/list_view" android:layout_width= "Match_" 
Parent " 
android:layout_height=" match_parent " 
/> 

<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout xmlns:android= 
 "http://schemas.android.com/" Apk/res/android " 
 android:layout_width=" match_parent " 
 android:layout_height=" Wrap_content " 
 android: padding= "4DP" 
 android:orientation= "Horizontal" > 
 
 <imageview android:id= "@+id/img" 
 android: Layout_width= "32DP" 
 android:layout_margin= "4DP" 
 android:layout_gravity= "center_vertical" 
 Android : layout_height= "32DP"/> 
 
 
 <textview android:id= "@+id/name" 
 android:textsize= "18sp" 
 android: Textstyle= "Bold" 
 android:layout_width= "match_parent" 
 android:gravity= "center_vertical" 
 android: layout_height= "50DP"/> 
 
</LinearLayout> 

Then create a new fileexploreractivity as the activity for the file selector, as follows:

public class Fileexploreractivity extends Appcompatactivity implements Adapterview.onitemclicklistener {ListView lis 
 Tview; 
 Simpleadapter adapter; 
 String RootPath = Environment.getexternalstoragedirectory (). GetPath (); 
 String Currentpath = RootPath; 
 
 list<map<string, object>> list = new arraylist<> (); 
 @Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); 
 Setcontentview (R.layout.activity_file_explorer); 
 ListView = (ListView) Findviewbyid (R.id.list_view); adapter = new Simpleadapter (this, list, R.layout.list_item, new string[]{"name", "IMG"}, new Int[]{r.id.name, r.id.img} 
 ); 
 Listview.setadapter (adapter); 
 Listview.setonitemclicklistener (this); 
 Refreshlistitems (Currentpath); 
 private void Refreshlistitems (String path) {settitle (path); 
 file[] files = new File (path). Listfiles (); 
 List.clear (); if (Files!= null) {for (File file:files) {map<string, object> Map = new hasHmap<> (); 
  if (File.isdirectory ()) {map.put ("img", r.drawable.directory); 
  else {map.put ("img", R.drawable.file_doc); 
  } map.put ("Name", File.getname ()); 
  Map.put ("Currentpath", File.getpath ()); 
  List.add (map); 
 } adapter.notifydatasetchanged (); @Override public void Onitemclick (adapterview<?> parent, View v, int position, long id) {Currentpath = (S 
 Tring) List.get (position). Get ("Currentpath"); 
 File File = new file (Currentpath); 
 if (File.isdirectory ()) Refreshlistitems (Currentpath); 
  else {Intent Intent = new Intent (); 
  Intent.putextra ("Apk_path", File.getpath ()); 
  Setresult (RESULT_OK, intent); 
 Finish (); 
 @Override public void onbackpressed () {if (Rootpath.equals (Currentpath)) {super.onbackpressed (); 
  else {File File = new file (Currentpath); 
  Currentpath = File.getparentfile (). GetPath (); 
 Refreshlistitems (Currentpath); 
 } 
 } 
}

This part of the code is not related to the thrust of our paper, mainly to facilitate the demo display, so I will not be explained.

Next, modify the code in Mainactivity as follows:

/** * Imitation 360 mobile phone helper second pack and intelligent installation function of the main activity. * Original address: http://blog.csdn.net/guolin_blog/article/details/47803149 * @author Guolin * @since 2015/12/7/Public Clas 
 
 S mainactivity extends appcompatactivity {TextView apkpathtext; 
 
 String Apkpath; 
 @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); 
 Setcontentview (R.layout.activity_main); 
 Apkpathtext = (TextView) Findviewbyid (R.id.apkpathtext); @Override protected void Onactivityresult (int requestcode, int resultcode, Intent data) {if (Requestcode = 0 & 
  amp;& ResultCode = = RESULT_OK) {Apkpath = Data.getstringextra ("Apk_path"); 
 Apkpathtext.settext (Apkpath); 
 } public void Onchooseapkfile (view view) {Intent Intent = new Intent (this, fileexploreractivity.class); 
 Startactivityforresult (Intent, 0); The public void Onsilentinstall (view view) {if (!isroot ()) {Toast.maketext (this, "cannot be installed without root permissions, cannot be used in seconds", toast.length_ 
  Short). Show (); ReturN } if (Textutils.isempty (Apkpath)) {Toast.maketext (this, select Install package!) 
  ", Toast.length_short). Show (); 
 Return 
 Final button button = (Button) view; 
 Button.settext ("Installation"); 
  New Thread (New Runnable () {@Override public void run () {Silentinstall installhelper = new Silentinstall (); 
  Final Boolean result = Installhelper.install (Apkpath); Runonuithread (New Runnable () {@Override public void run () {if (result) {Toast.maketext) (mainactivity.th IS, "Installation successful!" 
   ", Toast.length_short). Show (); else {toast.maketext (mainactivity.this, "Setup failed!") 
   ", Toast.length_short). Show (); 
   } button.settext ("Second Pack"); 
 
  } 
  }); 
 
 }). Start (); 
 public void onforwardtoaccessibility (view view) {} public void Onsmartinstall (view view) {}/** 
 * Determine whether the phone has root privileges. 
 * @return have root permission to return true, otherwise return false. 
 */Public Boolean isRoot () {Boolean bool = false; try {bool = new file ("/system/bin/su"). Exists () | | New file ("/system/xbiN/su "). exists (); 
 catch (Exception e) {e.printstacktrace (); 
 return bool; 
 } 
 
}

As you can see, in mainactivity, we have defined the callback method for the four button click events and call the Onchooseapkfile () method when you click the Select Package button, and the Onsilentinstall () method is invoked when you click the Second Mount button. In the Onchooseapkfile () method method, we open the fileexploreractivity through intent, and then read the selected APK file path in the Onactivityresult () method. In the Onsilentinstall () method, first to determine whether the device root, if there is no root directly return, and then determine whether the installation package has been selected, if not also direct return. Next we opened a thread to call the Silentinstall.install () method, because the installation process will be time-consuming, if not the thread will be stuck to the main thread, regardless of the success or failure of the installation, the end will be used toast to prompt.

So much for the code, and finally we're going to configure the Androidmanifest.xml file:

<?xml version= "1.0" encoding= "Utf-8"?> <manifest xmlns:android= 
"http://schemas.android.com/apk/res/" Android " 
 package=" Com.example.installtest "> 
 
 <uses-permission android:name=" Android.permission.READ_EXTERNAL_STORAGE "/> 
 
 <application 
 android:allowbackup=" true " 
 Android: icon= "@mipmap/ic_launcher" 
 android:label= "@string/app_name" 
 android:supportsrtl= "true" 
 Android: Theme= "@style/apptheme" > 
 <activity android:name= ". Mainactivity "> 
  <intent-filter> 
  <action android:name=" Android.intent.action.MAIN "/> 
 
  <category android:name= "Android.intent.category.LAUNCHER"/> 
  </intent-filter> 
 </ activity> 
 
 <activity android:name= ". Fileexploreractivity "/> 
 </application> 
 
</manifest> 

And there is no special place, because the choice APK file needs to read SD card, so in the Androidmanifest.xml file to remember to declare read SD card permissions.

It is also important to note that in the Android 6.0 system, read and write SD card permissions are listed as dangerous permissions, So if you specify the program's targetsdkversion to be 23, then you need to do a special 6.0 fit, and here's the simple reason why I've designated targetsdkversion as 22, because 6.0 of the fitness work is not covered by the article.

Now run the program, you can try a second load function, remember that the phone must root, the effect as shown in the following figure:

Can see, here we selected NetEase News installation package has been successfully installed on the phone, and there is no pop-up system installation interface, which proves that the second-pack function has been successfully implemented.

Second, intelligent installation

So for root mobile phone, the second load can really avoid the pop-up system installation interface, without affecting the user operation of the situation to achieve silent installation, but for the vast majority of mobile phones without root, this function is not available. So what should we do? For this 360 mobile phone assistants offer a compromise, using the barrier-free services provided by Android to enable intelligent installation. The so-called intelligent installation is not really a silent installation, because it still has to eject the system installation interface, but can be in the installation interface to release the user's operation, by intelligent installation function to simulate user clicks, after the installation is completed automatically shut down the interface. This feature is required to be manually turned on by the user and supports only the Android 4.1 phone, as shown in the following illustration:

OK, so next we're going to imitate the 360 phone assistants to implement similar smart installation functions.

The realization principle of intelligent install function to use the barrier-free service provided by Android, the detailed explanation of the barrier-free service can refer to the Official document: http://developer.android.com/guide/topics/ui/accessibility/ Services.html.

First, create a new Accessibility_service_config.xml file in the Res/xml directory, as shown in the following code:

<accessibility-service xmlns:android= "http://schemas.android.com/apk/res/android" 
   android:packagenames= " Com.android.packageinstaller " 
   android:description=" @string/accessibility_service_description " 
   android: Accessibilityeventtypes= "Typeallmask" 
   android:accessibilityflags= "Flagdefault" 
   android: Accessibilityfeedbacktype= "Feedbackgeneric" 
   android:canretrievewindowcontent= "true" 
 /> 

Where packagenames specifies the window activity under which the application is to be monitored, where a com.android.packageinstaller is written to monitor the installation interface of the Android system. Description Specifies the instructions that are displayed to the user in the barrier-free service, a large segment of the 360 handset assistants above is specified here. ACCESSIBILITYEVENTTYPES Specifies what events we can simulate in the listening window, where writing typeallmask indicates that all events can be simulated. Accessibilityflags can specify some additional parameters for the barrier-free service, where we pass the default value of Flagdefault. Accessibilityfeedbacktype Specify the feedback of accessibility services, in fact, the barrier-free service This feature is available to some people with disabilities, such as the blind person is not convenient to use the mobile phone, you can access to help the voice feedback to operate the mobile phone, And we actually do not need feedback, so random pass a value can, here passed Feedbackgeneric. Finally canretrievewindowcontent specifies whether to allow our program to read the nodes and contents in the window, and must write true.

Remember to write in the String.xml file what you specified in description, as follows:

<resources> 
 <string name= "app_name" >InstallTest</string> 
 <string name= " Accessibility_service_description > Intelligent Installation Services, you can install programs automatically without any user action. </string> 
</resources>

Next, modify the Androidmanifest.xml file, and configure the barrier-free service inside:

 <?xml version= "1.0" encoding= "Utf-8"?> <manifest "xmlns:android=" Schemas.android.com/apk/res/android "package=" Com.example.installtest "> <uses-permission android:name=" Android.permission.READ_EXTERNAL_STORAGE "/> <application android:allowbackup=" true "android:icon=" @mipmap/I  
 
 C_launcher "android:label=" @string/app_name "android:supportsrtl= true" android:theme= "@style/apptheme" > ... <service android:name= ". Myaccessibilityservice "android:label=" My Smart Install "android:permission=" Android.permission.BIND_ACCESSIBILITY_SERVICE "> <intent-filter> <action android:name=" Android.accessibilityservice.AccessibilityService "/> ;/intent-filter> <meta-data android:name= "Android.accessibilityservice" android:resource= "@xml/accessibil Ity_service_config "/> </service> </application> </manifest> 

The content of this part of the configuration is mostly fixed, you must declare a Android.permission.BIND_ACCESSIBILITY_SERVICE permission, And you have to have an action with a value of android.accessibilityservice.AccessibilityService, and then we specify the configuration file we just created by <meta-data>.

The next step is to implement the specific logic of the intelligent installation function, create a Myaccessibilityservice class and inherit from Accessibilityservice, the code looks like this:

/** * Implementation classes for intelligent installation features. * Original address: http://blog.csdn.net/guolin_blog/article/details/47803149 * @author Guolin * @since 2015/12/7/Public Clas S Myaccessibilityservice extends Accessibilityservice {map<integer, boolean> handledmap = new HashMap<> () 
 
 ; Public Myaccessibilityservice () {} @Override the public void Onaccessibilityevent (Accessibilityevent event) {Acces 
 Sibilitynodeinfo nodeinfo = Event.getsource (); 
  if (nodeinfo!= null) {int eventtype = Event.geteventtype (); 
   if (eventtype== accessibilityevent.type_window_content_changed | | EventType = = accessibilityevent.type_window_state_changed) {if (Handledmap.get (Event.getwindowid ()) = = null) {Boo 
   Lean handled = Iteratenodesandhandle (nodeinfo); 
   if (handled) {Handledmap.put (Event.getwindowid (), true); 
  Private Boolean Iteratenodesandhandle (Accessibilitynodeinfo nodeinfo) {if (nodeinfo!= null) { 
  int childcount = Nodeinfo.getchildcount (); if ("anDroid.widget.Button ". Equals (Nodeinfo.getclassname ())) {String nodecontent = Nodeinfo.gettext (). toString (); 
  LOG.D ("TAG", "content is" + nodecontent); if ("Install". Equals (nodecontent) | | "Done". Equals (nodecontent) | | 
   "OK". Equals (Nodecontent)) {nodeinfo.performaction (Accessibilitynodeinfo.action_click); 
  return true; } else if ("Android.widget.ScrollView". Equals (Nodeinfo.getclassname ())) {Nodeinfo.performaction (Accessibilitynode 
  Info.action_scroll_forward); 
  for (int i = 0; i < ChildCount i++) {Accessibilitynodeinfo childnodeinfo = Nodeinfo.getchild (i); 
  if (Iteratenodesandhandle (Childnodeinfo)) {return true; 
 }} return false; 
 @Override public void Oninterrupt () {}}

The code is not complicated, let's parse it. Whenever the window is active, a message is recalled to the Onaccessibilityevent () method, so all logic starts here. First we can get the type of the current event by passing in the accessibilityevent argument, but we only need to listen for type_window_content_changed and Type_window_state_ Changed these two events are possible, because one of these two events must be triggered throughout the installation process. Of course there are two possible simultaneous triggers, so in order to prevent two-time processing, here we use a map to filter out repetitive events.

The next step is to call the Iteratenodesandhandle () method to parse the node of the current interface, where we iterate through all the child nodes in the installation interface, and when the button nodes are found, the text on the button is not "Install", "Finish", "OK" These types, if yes, simulate the Click event, which is equivalent to help users automatically manipulate these buttons. In addition, starting with the Android 4.4 system, users need to read all the permissions of the application to click on the installation, so if we find ScrollView in the node, then simulate the slide event, slide the interface to the bottom, so the installation button can be clicked.

Finally, go back to mainactivity to add a call to the Smart Install feature, as follows:

/** 
 * Imitation 360 mobile phone helper second pack and intelligent installation function of the main activity. 
 * Original Address: http://blog.csdn.net/guolin_blog/article/details/47803149 
 * @author guolin 
 * @since 2015/12/7 
 * * Public 
class Mainactivity extends Appcompatactivity { 
 
 ... 
 
 public void onforwardtoaccessibility (view view) { 
 Intent Intent = new Intent (settings.action_accessibility_ SETTINGS); 
 StartActivity (intent); 
 } 
 
 public void Onsmartinstall (view view) { 
 if (Textutils.isempty (Apkpath)) { 
  Toast.maketext (this), select Install package! ", Toast.length_short). Show (); 
  return; 
 } 
 Uri uri = uri.fromfile (new File (Apkpath)); 
 Intent localintent = new Intent (intent.action_view); 
 Localintent.setdataandtype (URI, "application/vnd.android.package-archive"); 
 StartActivity (localintent); 
 } 
 
 

When you click on the Smart Install Service button, we jump to the system's barrier-free service interface via intent, where we start intelligent installation Services. When the Smart Install button is clicked, we jump to the installation interface of the system through intent, and all the installation operations will be completed automatically.

Now you can rerun the program, as shown in the following illustration:

Can be seen, when the installation of NetEase news installed interface, we do not need to do any manual operation, the interface of the sliding, installation button, complete button click is automatically completed, will eventually automatically return to the original interface state of the phone, which is modeled on the 360 mobile phone assistant implementation of the intelligent installation function.

All right, so here's what this article is all about, although it can not be said that the full implementation of silent installation, but we have been allowed within the scope of permission to do as far as possible, and 360 of mobile phone assistants can only achieve this step, those who have been forced by product managers to implement a silent installation of the procedures are also a reason to do it?

SOURCE Download: Http://xiazai.jb51.net/201611/yuanma/AndroidInstallTest (jb51.net). rar

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.