Help us understand the problem. What is going on with this article?

Oreo対応した話

More than 1 year has passed since last update.

担当サービスの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

https://github.com/firebase/firebase-jobdispatcher-android

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)

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

まとめ

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

nbhd
cyberagent
サイバーエージェントは「21世紀を代表する会社を創る」をビジョンに掲げ、インターネットテレビ局「AbemaTV」の運営や国内トップシェアを誇るインターネット広告事業を展開しています。インターネット産業の変化に合わせ新規事業を生み出しながら事業拡大を続けています。
http://www.cyberagent.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした