Search code examples
androidflutterandroid-tvamazon-fire-tv

How do I make may Android TV App relaunch after a crash


I'm building a corporate app for android TV that I need to have always in the foreground. Every now and then the app will crash along with the service that will relaunch it. Is there a best practice to ensure the app is always running. What I can't figure out is how to launch after a force stop. The app can be side loaded so we don't have to worry about App Store approval.

The problem is when I use a service worker it will also die since it is attached to the original process https://developer.android.com/reference/android/app/Service

Same issue with the https://developer.android.com/topic/libraries/architecture/workmanager

Any ideas on an approach to basically check if the app is running and if it isn't start it up ? Is there any other event that I can hook into to launch the app ?


Solution

  • If a crash happens the app will rerun itself:

     class AppExceptionHandler(private val context: Context, private val myActivityClass: Class<*>) :
        Thread.UncaughtExceptionHandler {
        override fun uncaughtException(thread: Thread, exception: Throwable) {
            Logger.d(exception.javaClass.simpleName)
                exception.printStackTrace()
                val intent = Intent(context, myActivityClass)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
    
                context.startActivity(intent)
                //restarting the Activity
                Process.killProcess(Process.myPid())
                System.exit(0)
        }
    }
    

    and call from your main activity:

      Thread.setDefaultUncaughtExceptionHandler(
            AppExceptionHandler(
                applicationContext,
                MainActivity::class.java
            )
        )
    

    In this way, I don't think you need to know whether the app is now in the foreground and running but you can get the top running package name in a running service. Also making your app a default launcher could be a workaround.

       fun topPackageNameObservable(): Observable<String?>? {
            return Observable.fromCallable {
                var topPackageName = ""
                try {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        val mUsageStatsManager =
                            getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
                        val stats =
                            mUsageStatsManager.queryUsageStats(
                                UsageStatsManager.INTERVAL_DAILY,
                                System.currentTimeMillis() - TimeUnit.DAYS.toMillis(
                                    1
                                ),
                                System.currentTimeMillis() + TimeUnit.DAYS.toMillis(
                                    1
                                )
                            )
                        if (stats != null) {
                            val mySortedMap: SortedMap<Long, UsageStats> =
                                TreeMap()
                            for (usageStats in stats) {
                                mySortedMap[usageStats.lastTimeUsed] = usageStats
                            }
                            if (!mySortedMap.isEmpty()) {
                                topPackageName = mySortedMap[mySortedMap.lastKey()]!!.packageName
                            }
                        } else {
                            topPackageName = activityManager.getRunningAppProcesses().get(0).processName
                        }
                    } else {
                        topPackageName =
                            activityManager.getRunningTasks(1).get(0).topActivity.getPackageName()
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
                topPackageName
            }
        }
    

    Try using PackageManager and getLaunchIntentForPackage()