LoginSignup
38
31

More than 5 years have passed since last update.

Oreo対応した話

Last updated at Posted at 2017-11-30

担当サービスのOreo対応した話。
targetSdkVersion を 26にあげると対応が必須になる。
対応は主にここに書いてあることをやることになる。
Background Execution Limits | Android Developers
以下やったこと、ハマったところを列挙。

NotificationChannel の追加

通知が届かなくなるので対応必須。
このあたりを参考にした。
https://github.com/googlesamples/android-testdpc/blob/master/app/src/main/java/com/afwsamples/testdpc/common/NotificationUtil.java

暗黙的broadcastを明示的broadcastへ置き換え

android.intent.action.PACKAGE_REMOVEDandroid.intent.action.MY_PACKAGE_REPLACED に置き換え。
https://developer.android.com/about/versions/oreo/background.html#broadcasts
担当サービスはこれだけだったが、他にも色々あるので要確認。

background で動かしている Service の対応

ここに書いてあるように、background で startService() が呼ばれるものはクラッシュするので対応する。
https://developer.android.com/about/versions/oreo/background.html#migration

ただし、

NotificationManager.startServiceInForeground() instead of startService().

と書いてあるが、実際は ContextCompat.startServiceInForeground()
上記メソッドを叩いた後、 Service.startForeground() 5秒以内に呼ばないとクラッシュする(break point で止めても例外なし)など色々曲者。
こちらにNGケースが詳しく書いてある。
Android Oからのバックグラウンド・サービスの制限事項を実演する。 - Qiita

また、 WakefulBroadcastReceiver は内部で startService() を使用しているのでクラッシュする。
もともと deprecated だったのでこのタイミングで完全廃止。
BroadcastReceiver にして、後述の JobDispatcher と組み合わせる。

対応にあたって、IntentService を使い続けるのはしんどかったので、該当の Service は JobScheduler に置き換えることにした。
しかし担当サービスの minSDK が 16 以上なこともあり、 Firebase の JobDispatcher を導入する。
21以上だったら JobScheduler を使うといいと思う。

JobDispatcher

backgroundから呼ばれる Service を job に置換していく。
大枠こんな感じ。

before

AndroidManifest.xml
<service android:name=".MyIntentService"/>
public class MyIntentService extends IntentService {        

    public MyIntentService() {      
        super("MyIntentService");       
    }       

    public static void startService(final Context context) {        
        context.startService(new Intent(context, MyIntentService.class));       
    }       

    @Override       
    protected void onHandleIntent(final Intent intent) {        
        // do something
    }       
}

after (kotlin 化もついでに..)

AndroidManifest.xml
<service
      android:name=".MyJobService"
      android:exported="false">
      <intent-filter>
          <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
      </intent-filter>
</service>
class MyJobService : SimpleJobService() {

  override fun onRunJob(parameters: JobParameters?): Int {
    // do something
    return JobService.RESULT_SUCCESS
  }
}

呼び出し

val dispatcher: FirebaseJobDispatcher = FirebaseJobDispatcher(GooglePlayDriver(context))
val myJob: Job = dispatcher.newJobBuilder()
    .setService(MyJobService::class.java)
    .setTag("my-unique-tag")
    .setTrigger(Trigger.NOW) // NOW と言いつつも、30秒後ぐらいに発動する
    .build()

dispatcher.mustSchedule(myJob)

他にも色々オプション設定があるので公式参照。

まとめ

ここまで終わったら後はひたすら動作確認!

38
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
31