androidandroid-8.0-oreojobintentservice

Start a JobIntentService Implicitly


As you know this is how we fire a JobIntentService:

JobIntentService.enqueueWork(this,
                        MyJobIntentService.class,
                        JOB_ID, 
                        intent);

In this approach we KNOW which service we want to start and pass its class to the method.
Here is my question: Is there any way to start a service implicitly ?
Why I need this ? I'm developing a library that sometimes should start a service that developer extends and obviously I have no access to it from library
What I tried? I implemented it with IntentService (using intent filters) and worked fine for pre O devices but for Android Oreo I'm receiving this crash log:

Fatal Exception: java.lang.IllegalStateException: Not allowed to start service Intent { act=someAction pkg=somePackage (has extras) }: app is in background uid UidRecord{de24eda u0a238 RCVR idle procs:1 seq(0,0,0)}

So I moved to JobIntentService, now the problem is that I can't start it implicitly.
Any solution or alternative will be appreciated.


Solution

  • Well, I found a solution, first query for service you're looking for and check if has the necessary permission for JobIntentService, then enqueue work :

    private final String PERMISSION_BIND_JOB_SERVICE = "android.permission.BIND_JOB_SERVICE";
    Intent handlerIntent = new Intent(MY_ACTION);
    List<ResolveInfo> result =
            getPackageManager().queryIntentServices(handlerIntent, 0);
                if (result.size() > 0) {
        ResolveInfo info = result.get(0);
        if (info != null && info.serviceInfo != null &&
                info.serviceInfo.permission != null){
            String permission = info.serviceInfo.permission;
            if (permission.equals(PERMISSION_BIND_JOB_SERVICE)) {
                try {
                    Class<?> serviceClass = Class.forName(info.serviceInfo.name);
                    JobIntentService.enqueueWork(this,
                            serviceClass,
                            JOB_ID, handlerIntent);
    
                } catch (ClassNotFoundException e) {
                    //Handle exception if you will
                }
            }
        }
    }
    

    And in app module manifest I added android.permission.BIND_JOB_SERVICE to my service as well:

    <service
        android:name=".MyService"
        android:enabled="true"
        android:permission="android.permission.BIND_JOB_SERVICE"
        android:exported="false">
        <intent-filter>
            <action android:name="MY_ACTION" />
        </intent-filter>
    </service>