2

I need to deploy and update various enterprise applications to Android devices given to a limited number of users.

These applications are not supposed to be published on Google Play but must be distributed via a separate channel.

What I need to do is an "enterprise package manager" application to automatically check for new apps/updates and automatically trigger installation of new or updated APKs without asking user consent first.

I know that, by design, Android doesn't allow 3rd party applications to interact with installed applications. I also know that rooted phones don't have this problem because you can inject any APK into the device.

  • If I cook a ROM (even based on CWM) with the "enterprise package manager" installed as system application, but without su binary (it's still an enterprise phone...), will that program be able to install new apps automatically?
  • How am I supposed to install an application without asking for consent? I mean, I need a basic code sample and permissions, if required
  • Anyway, do system apps run as root user? I remember so
usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305

1 Answers1

3

If you want to check for your application which is on somewhere on your server you have to check for Update in every 24 hour once, if there is any update available then it will navigate to the async task where your updated version build will get installed

public void checkforUpdate() {

        /* Get Last Update Time from Preferences */
        SharedPreferences prefs = getPreferences(0);
        lastUpdateTime = prefs.getLong("lastUpdateTime", 0);
        if ((lastUpdateTime + CommonString.timeCheckDuration) < System.currentTimeMillis() && System.currentTimeMillis()>lastUpdateTime) {
            // Asynch task
            new VersionCheckTask().execute();
        }
        else{
            // do nothing
        }
    }

now it will navigate to:

private class VersionCheckTask extends AsyncTask<Void, Void, Void> {
        ProgressDialog progressDialog;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            try {
                progressDialog = new ProgressDialog(Login.this, android.R.style.Theme_Holo_Light_Dialog);
                //progressDialog.setTitle("AppName");
                progressDialog.setMessage("Checking for updates...");
                progressDialog.setCancelable(false);
                progressDialog.setIndeterminate(true);
                progressDialog.show();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        protected Void doInBackground(Void... params) {
            /**
             *  Simulates a background job.
             */
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }

            HashMap<String, String> map = new HashMap<String, String>();
            map.put("build",CommonString.buildVersion);
            map.put("en", CommonString.en);

            responce = CommonFunction.PostRequest("updateCheck", map);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if (progressDialog != null && progressDialog.isShowing())
                progressDialog.dismiss();
            if(!CommonFunction.isNetworkAvailable()){
                Toast.makeText(ClaimColonyApplication.getAppContext(), CommonString.NO_NETWORK, Toast.LENGTH_SHORT).show();
                return;
            }
            ParseUpdateResponse(responce);
            if(rCodeUpdate == 100 && ApkLink.length() >0){
                new AlertDialog.Builder(Login.this,android.R.style.Theme_Holo_Light_Dialog)
                .setIcon(R.drawable.ic_launcher)
                .setTitle("Update Available")
                .setMessage(""+UpdateMessage)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                         //User clicked OK so do some stuff 
                        new VersionCheckTaskDialog().execute();
                    }
                })
                .setNegativeButton("No", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                         //User clicked Cancel 
                        finish();
                    }
                })
                .show();
            }else{
                if(rCodeUpdate == 100){
                    lastUpdateTime = System.currentTimeMillis();
                    SharedPreferences.Editor editor = getPreferences(0).edit();
                    editor.putLong("lastUpdateTime", lastUpdateTime);

                    editor.commit();
                }
            }
            super.onPostExecute(result);
        }
    }

    private class VersionCheckTaskDialog extends AsyncTask<Void, Void, Void> {
        ProgressDialog progressDialogUpdate;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            try {
                progressDialogUpdate = new ProgressDialog(Login.this, android.R.style.Theme_Holo_Light_Dialog);
                //progressDialog.setTitle("AppName");
                progressDialogUpdate.setMessage("Fetching updates...");
                progressDialogUpdate.setCancelable(false);
                progressDialogUpdate.setIndeterminate(true);
                progressDialogUpdate.show();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        protected Void doInBackground(Void... params) {
            /**
             *  Simulates a background job.
             */
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }

            String extStorageDirectory =    Environment.getExternalStorageDirectory().toString();
            File folder = new File(extStorageDirectory, "pdf");
            folder.mkdir();
            File file = new File(folder, "AppName."+"apk");
            try {
                    file.createNewFile();
            } catch (IOException e1) {
                    e1.printStackTrace();
            }
            /**
             * replace url to ApkLink
             */
             //DownloadFile(ApkLink, file);
             DownloadFile("URL", file);

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if (progressDialogUpdate != null && progressDialogUpdate.isShowing())
                progressDialogUpdate.dismiss();
            if(!CommonFunction.isNetworkAvailable()){
                Toast.makeText(ClaimColonyApplication.getAppContext(), CommonString.NO_NETWORK, Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/pdf/" + "AppName.apk")), "application/vnd.android.package-archive");
                startActivity(intent);
                lastUpdateTime = System.currentTimeMillis();
                SharedPreferences.Editor editor = getPreferences(0).edit();
                editor.putLong("lastUpdateTime", lastUpdateTime);

                editor.commit();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                System.out.println("Exception in start intent for launch app-------: "+e.toString());
                e.printStackTrace();
            } 
            super.onPostExecute(result);
        }
    }

I am checking for update once in 24 hours, if there is any update available then it will show pop up to upgrade your application otherwise will save your last checking time in Preferences. Now this will allow you to update and install your application and this will check for next update after 24 hours, you may need to work on conditions to check for update. Please change name of your .apk file and URL.

You will need following permissions:

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Best of luck.

Youngjae
  • 24,352
  • 18
  • 113
  • 198
Puneet
  • 611
  • 6
  • 22
  • Thanks for the code. That was probably not what I really wanted to ask. I mean... querying for application updates is very simple task. The VersionCheckTaskDialog's onPostExecute is the most interesting part. What I need to do there is to trigger an **unsupervisioned** installation. Your code is *supposed* to ask for user consent, but since I haven't tested it and since because it should be an "on-paper" proof of concept I want to ask you if triggering the ACTION_VIEW intent from a system app can trigger an unsupervisioned installation. Thanks – usr-local-ΕΨΗΕΛΩΝ Dec 12 '12 at 09:37
  • 1
    I am also doing the same but here I am forcing user to update his version until he will not update he will not be able to login in app, when there is any update available on my server, i will get some url of my new build and i show pop up, if user allow to update is will automatically download application apk in device and ask to install, after installation user will have to start app again, – Puneet Dec 12 '12 at 09:48
  • +1 for being a feasible way to enforce the latest release rule – usr-local-ΕΨΗΕΛΩΝ Dec 12 '12 at 10:09