{"id":22165824,"url":"https://github.com/tutorialsandroid/backgroundappupdater","last_synced_at":"2026-05-10T16:47:06.232Z","repository":{"id":114468246,"uuid":"255820180","full_name":"TutorialsAndroid/BackgroundAppUpdater","owner":"TutorialsAndroid","description":"A sample demostration that how to update app externally from website using JSOUP","archived":false,"fork":false,"pushed_at":"2020-05-23T14:14:09.000Z","size":9784,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-08T08:47:09.903Z","etag":null,"topics":["android","android-application","android-demo","android-development","update-checker"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TutorialsAndroid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-15T06:02:10.000Z","updated_at":"2025-06-02T07:35:05.000Z","dependencies_parsed_at":"2023-03-21T08:54:32.359Z","dependency_job_id":null,"html_url":"https://github.com/TutorialsAndroid/BackgroundAppUpdater","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TutorialsAndroid/BackgroundAppUpdater","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TutorialsAndroid%2FBackgroundAppUpdater","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TutorialsAndroid%2FBackgroundAppUpdater/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TutorialsAndroid%2FBackgroundAppUpdater/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TutorialsAndroid%2FBackgroundAppUpdater/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TutorialsAndroid","download_url":"https://codeload.github.com/TutorialsAndroid/BackgroundAppUpdater/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TutorialsAndroid%2FBackgroundAppUpdater/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32864092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"ssl_error","status_checked_at":"2026-05-10T13:40:02.145Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-application","android-demo","android-development","update-checker"],"created_at":"2024-12-02T05:16:47.241Z","updated_at":"2026-05-10T16:47:06.199Z","avatar_url":"https://github.com/TutorialsAndroid.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BackgroundAppUpdater\n\n**This sample app will demonstrate you to how to update your app in foreground. This tutorial will also explain you how to update your app from external website using JSOUP library. This is just sample demonstration apply your some logic if you have any problems or contact me.**\n\n\n[`Heatic Debate App Download Now`](https://play.google.com/store/apps/details?id=com.asm.heatic)\n\n## And Don't Forget To Follow Me On Instagram\n\n\u003cp align=\"center\"\u003eFollow me on instagram to stay up-to-date https://instagram.com/akshaysunilmasram \n\n`We will use github to check app version update. Create update.md file somewhere in your git repo and put this code in it`\n\n\t\u003cdiv class=\"content\" itemprop=\"softwareVersion\"\u003e4.0\u003c/div\u003e\n\n\n`Put this in your build.gradle file`\n\n\t// jsoup HTML parser library @ https://jsoup.org/\n    implementation 'org.jsoup:jsoup:1.13.1'\n\n`Now create a xml file named as provider_paths`\n\n\t\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\t\u003cpaths\u003e\n    \t\u003cexternal-path name=\"external_files\" path=\".\"/\u003e\n\t\u003c/paths\u003e\n\n`This will be your manifest file`\n\n\t\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\t\u003cmanifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.myapplication\"\u003e\n\n    \u003cuses-permission android:name=\"android.permission.INTERNET\"/\u003e\n    \u003cuses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/\u003e\n    \u003cuses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/\u003e\n    \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/\u003e\n    \u003cuses-permission android:name=\"android.permission.DOWNLOAD_WITHOUT_NOTIFICATION\" /\u003e\n    \u003cuses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/\u003e\n\n    \u003capplication\n        android:label=\"@string/app_name\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        android:allowBackup=\"true\"\n        android:fullBackupContent=\"true\"\u003e\n\n        \u003cactivity android:name=\"com.example.myapplication.MainActivity\"\u003e\n            \u003cintent-filter\u003e\n                \u003caction android:name=\"android.intent.action.MAIN\" /\u003e\n\n                \u003ccategory android:name=\"android.intent.category.LAUNCHER\" /\u003e\n            \u003c/intent-filter\u003e\n        \u003c/activity\u003e\n\n        \u003cservice android:name=\"com.example.myapplication.BackgroundService\"\n            android:exported=\"true\"/\u003e\n\n        \u003cprovider\n            android:name=\"androidx.core.content.FileProvider\"\n            android:authorities=\"${applicationId}.provider\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\"\u003e\n            \u003cmeta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/provider_paths\"/\u003e\n        \u003c/provider\u003e\n    \u003c/application\u003e\n\t\u003c/manifest\u003e\t\n\n`Now make a java class file named as BackgroundService in your package. And please note that your apk file name should be main.apk because i used main.apk filename to check in device storage weather the app is present or not you can give any other name too but the name once given should not be changed.`\n\n\tpublic class BackgroundService extends Service {\n\n    private final static int INTERVAL = 1000 * 60 * 2; //2 minutes\n    Handler mHandler = new Handler();\n\n    //This is path used for checking apk file is present or not in downloads directory\n    private static File apkPath = new File(Environment.getExternalStoragePublicDirectory\n            (Environment.DIRECTORY_DOWNLOADS), \"main.apk\"); //here i have gived app name as main.apk if your app fileName is different then //please update here also\n\n    @Override\n    public void onCreate(){\n        super.onCreate();\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O)\n            startMyOwnForeground();\n        else\n            startForeground(2, new Notification());\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.O)\n    private void startMyOwnForeground(){\n        String NOTIFICATION_CHANNEL_ID = \"com.example.myapplication\";\n        String channelName = \"BackgroundApp\";\n\n        NotificationChannel notificationChannel =\n                new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,\n                        NotificationManager.IMPORTANCE_NONE);\n\n        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        Objects.requireNonNull(manager).createNotificationChannel(notificationChannel);\n\n        NotificationCompat.Builder notificationBuilder =\n                new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);\n\n        Notification notification = notificationBuilder.setOngoing(true)\n                .setSmallIcon(R.mipmap.ic_launcher)\n                .setContentTitle(\"App is running in background\")\n                .setPriority(NotificationManager.IMPORTANCE_MIN)\n                .setCategory(Notification.CATEGORY_SERVICE)\n                .build();\n\n        startForeground(2, notification);\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent)\n    {\n        return null;\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId)\n    {\n        // do your jobs here\n        startTask();\n        return super.onStartCommand(intent, flags, startId);\n\n    }\n\n    Runnable mHandlerTask = new Runnable()\n    {\n        @Override\n        public void run()\n        {\n            new FetchAppVersion(BackgroundService.this).execute();\n\n            mHandler.postDelayed(mHandlerTask, INTERVAL);\n        }\n    };\n\n    void startTask()\n    {\n        mHandlerTask.run();\n    }\n\n    public static class FetchAppVersion\n            extends AsyncTask\u003cString, Void, String\u003e {\n\n        @SuppressLint(\"StaticFieldLeak\")\n        private Context context;\n\n        FetchAppVersion(Context context) {\n            this.context = context;\n        }\n\n        protected String doInBackground(String... urls)\n        {\n            try {\n                return\n                        //Put your github url where you have located update.md file in github\n                        //like i have used update.md file url. you should replace this url with your own.\n                        Jsoup.connect(\"https://github.com/TutorialsAndroid/BackgroundAppUpdater/blob/master/app/update.md\")\n                                .timeout(10000)\n                                .userAgent(\"Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6\")\n                                .referrer(\"http://www.github.com\")\n                                .get()\n                                .select(\"div[itemprop=softwareVersion]\")\n                                .first()\n                                .ownText();\n\n            } catch (Exception e) {\n                return \"\";\n            }\n        }\n\n        protected void onPostExecute(String string)\n        {\n            super.onPostExecute(string);\n            Log.d(\"new Version\", string);\n\n        try\n        {\n            String version = context.getPackageManager()\n                    .getPackageInfo(context.getPackageName(), 0).versionName;\n\n            //Now let's check if current app version is equals to uploaded\n            //apk version.        \n            if(!version.equals(string))\n            {\n                //Toast.makeText(context, \"New version available\",\n                        //Toast.LENGTH_SHORT).show();\n\n                //This method will check if app exits in storage or not\n                //if it exits then delete it first and download new one\n                if (apkPath.exists()) {\n                    //noinspection ResultOfMethodCallIgnored\n                    apkPath.delete(); //old apk deleted now go for a download task\n                }\n                downloadManager();\n            }\n\n        }\n        catch (PackageManager.NameNotFoundException e)\n        {\n            //No version do something\n        }\n\n        }\n\n        private void downloadManager()\n        {\n            //Path where the apk will be downloaded. here i have gived app name as main.apk if your app fileName is different then change it here also\n            //File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + \"main.apk\");\n\n            //Replace with your file url where you uploaded your apk someWhere on the internet\n            String URL = \"https://github.com/TutorialsAndroid/BackgroundAppUpdater/raw/master/app/main.apk\";\n            DownloadManager.Request request = new DownloadManager.Request(\n                    Uri.parse(URL)\n            );\n\n            //Here we will guess fileName and fileExtension\n            String fileExtenstion = MimeTypeMap.getFileExtensionFromUrl(URL);\n            String name = URLUtil.guessFileName(URL, null, fileExtenstion);\n\n            // Title of the Download Notification\n            request.setTitle(name);\n\n            //TODO this method is deprecated now.\n            request.setVisibleInDownloadsUi(false);\n\n            // Description of the Download Notification\n            request.setDescription(\"Downloading Update\");\n\n            // Uri of the destination file\n            //request.setDestinationUri(Uri.fromFile(path));\n\n            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,name);\n\n            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);\n\n            DownloadManager downloadManager= (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);\n            // enqueue puts the download request in the queue.\n            Objects.requireNonNull(downloadManager).enqueue(request);\n\n            //This will check that apk download has completed.\n            context.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));\n        }\n\n        //This method will start a notification service when apk has been downloaded.\n        BroadcastReceiver onComplete = new BroadcastReceiver() {\n            public void onReceive(Context context, Intent intent) {\n\n                String channelId = \"noti\";\n                Log.d(\"onDownloadComplete\",\"Download Completed\");\n\n                if (android.os.Build.VERSION.SDK_INT \u003e= android.os.Build.VERSION_CODES.O) {\n                    String channelName = context.getString(R.string.app_name);\n                    NotificationChannel notificationChannel = new NotificationChannel(channelId,\n                            channelName, NotificationManager.IMPORTANCE_LOW);\n                    notificationChannel.setLightColor(Color.BLUE);\n                    notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);\n                    NotificationManager notificationManager = (NotificationManager)\n                            context.getSystemService(Context.NOTIFICATION_SERVICE);\n                    if (notificationManager != null) {\n                        notificationManager.createNotificationChannel(notificationChannel);\n                    }\n\n                    Uri uri = FileProvider.getUriForFile(context,\n                            BuildConfig.APPLICATION_ID + \".provider\",apkPath);\n\n                    NotificationManagerCompat notificationManagerCompat =\n                            NotificationManagerCompat.from(context);\n\n                    String contentTitle = \"New Update Ready To Install\";\n                    Intent notifyIntent = new Intent();\n                    notifyIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);\n                    notifyIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n                    notifyIntent.setData(uri);\n\n                    PendingIntent notifyPendingIntent =\n                            PendingIntent.getActivity(context, 3, notifyIntent,\n                                    PendingIntent.FLAG_UPDATE_CURRENT |\n                                            PendingIntent.FLAG_ONE_SHOT);\n\n                    NotificationCompat.Builder notificationBuilder =\n                            new NotificationCompat.Builder(context,channelId);\n                    notificationBuilder.setContentIntent(notifyPendingIntent);\n                    notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);\n                    notificationBuilder.setContentTitle(contentTitle);\n                    notificationManagerCompat.notify(4, notificationBuilder.build());\n                } else {\n                    intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);\n                    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n                    intent.setData(Uri.fromFile(apkPath));\n\n                    PendingIntent contentIntent = PendingIntent.getActivity(context, 0,\n                            intent, PendingIntent.FLAG_UPDATE_CURRENT);\n\n                    NotificationCompat.Builder b = new NotificationCompat.Builder(context,channelId);\n\n                    b.setAutoCancel(true)\n                            .setDefaults(Notification.DEFAULT_ALL)\n                            .setWhen(System.currentTimeMillis())\n                            .setSmallIcon(R.mipmap.ic_launcher)\n                            .setContentTitle(\"Update Complete\")\n                            .setContentText(\"Install the app now to latest version\")\n                            .setDefaults(Notification.DEFAULT_LIGHTS| Notification.DEFAULT_SOUND)\n                            .setContentIntent(contentIntent)\n                            .setContentInfo(\"Info\");\n\n                    NotificationManager notificationManager = (NotificationManager)\n                            context.getSystemService(Context.NOTIFICATION_SERVICE);\n                    Objects.requireNonNull(notificationManager).notify(4, b.build());\n                }\n            }\n        };\n    }\n\t}\n\n`And this will be used MainActivity Java Class file`\n\n    public class MainActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        if (android.os.Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.M) {\n            //Request Storage Permissions On Android Version 6.0 And Above\n            ActivityCompat.requestPermissions(MainActivity.this,\n                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,\n                            Manifest.permission.WRITE_EXTERNAL_STORAGE},\n                    1);\n        } else {\n            //Here we start the service\n            startService(new Intent(this, BackgroundService.class));\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode,\n                                           @NonNull String[] permissions,\n                                           @NonNull int[] grantResults)\n    {\n\n        if (requestCode == 1) {// If request is cancelled, the result arrays are empty.\n            if (grantResults.length \u003e 0\n                    \u0026\u0026 grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n\n                // permission was granted, yay! Do the\n                // contacts-related task you need to do.\n                //Toast.makeText(this, \"Permission Granted\", Toast.LENGTH_SHORT).show();\n                Log.d(\"PERMISSIONS\",\"GRANTED\");\n                //Here we start the service\n                startService(new Intent(this, BackgroundService.class));\n            } else {\n\n                // permission denied, boo! Disable the\n                // functionality that depends on this permission.\n                Toast.makeText(MainActivity.this, \"Permission denied to read your External storage\", Toast.LENGTH_SHORT).show();\n            }\n            // other 'case' lines to check for other\n            // permissions this app might request\n        }\n    }\n\t}\t\t\n\n## License\n\tCopyright 2020 TutorialsAndroid\n\t\n\tLicensed under the Apache License, Version 2.0 (the \"License\");\n\tyou may not use this file except in compliance with the License.\n\tYou may obtain a copy of the License at\n\t\n\t   http://www.apache.org/licenses/LICENSE-2.0\n\t\n\tUnless required by applicable law or agreed to in writing, software\n\tdistributed under the License is distributed on an \"AS IS\" BASIS,\n\tWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\tSee the License for the specific language governing permissions and\n\tlimitations under the License.\t    \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftutorialsandroid%2Fbackgroundappupdater","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftutorialsandroid%2Fbackgroundappupdater","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftutorialsandroid%2Fbackgroundappupdater/lists"}