skimemo


skimemo - 日記/2019-07-29

_ NativeScriptでServiceを実装する

NativeScriptでAndroidのサービスを実装する方法は概ねマニュアル通りなのですが、若干はまったのでメモです。

NativeScript+Serviceで検索するとこのへんとかが出てくるのですが、なんだか分かりづらいです。
私が参考にしたのはこちらでした。シンプルです。
以下、手順です。

  1. サービスの初期化
    app/app.jsに以下のように書きます。
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
    
    const utils = require("tns-core-modules/utils/utils");
    const application = require("tns-core-modules/application");
    const Platform = require("tns-core-modules/platform");
     
    const jobId = 1;
     
    function stopBackgroundJob() {
        if (application.android) {
            let context = utils.ad.getApplicationContext();
            const jobScheduler = context.getSystemService(android.content.Context.JOB_SCHEDULER_SERVICE);
            if (jobScheduler.getPendingJob(jobId) !== null) {
                jobScheduler.cancel(jobId);
                console.log(`initservice: Job Canceled: ${jobId}`);
            }
        }
    }
    // アプリを閉じたらサービスも止める
    // application.on(application.exitEvent, stopBackgroundJob);
     
    function startBackground() {
        console.log('startBackground sdkver='+Platform.device.sdkVersion);
        if (application.android) {
            let context = utils.ad.getApplicationContext();
            if (Platform.device.sdkVersion < "26") {
                let intent = new android.content.Intent(context, jp.inxray.scop.BackgroundService.class);
                context.startService(intent);
            } else {
                const jobScheduler = context.getSystemService(android.content.Context.JOB_SCHEDULER_SERVICE);
                const component = new android.content.ComponentName(context, jp.inxray.scop.BackgroundService26.class);
                const builder = new (android.app).job.JobInfo.Builder(jobId, component);
                builder.setOverrideDeadline(0);
                return jobScheduler.schedule(builder.build());
            }
        }
    }
     
    function stopBackgroundTap() {
        if (application.android) {
            if (Platform.device.sdkVersion < "26") {
                let context = utils.ad.getApplicationContext();
                let intent = new android.content.Intent(context, jp.inxray.scop.BackgroundService.class);
                context.stopService(intent);
            } else {
                stopBackgroundJob();
            }
        }
    }
     
    // 開始
    startBackground(); 

  2. サービス本体です
    app/service/background.js
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
    
    const application = require("tns-core-modules/application");
    const Timer = require("tns-core-modules/timer");
    const Platform = require("tns-core-modules/platform");
     
    let timerid = null;
     
    if (application.android) {
        if (Platform.device.sdkVersion < "26") {
            (android.app.Service).extend("jp.inxray.scop.BackgroundService", {
                onStartCommand: function (intent, flags, startId) {
                    this.super.onStartCommand(intent, flags, startId);
                    return android.app.Service.START_STICKY;
                },
                onCreate: function () {
                    startTimer(30);
                    console.log("background: start Service");
                },
                onBind: function (intent) {
                    console.log("background: on Bind Services");
                },
                onUnbind: function (intent) {
                    console.log('background: UnBind Service');
                },
                onDestroy: function () {
                    console.log('background: service onDestroy');
                    stopTimer();
                }
            });
        } else {
            (android.app).job.JobService.extend("jp.inxray.scop.BackgroundService26", {
                onStartJob() {
                    startTimer(30);
                    console.log('background: service onStartJob');
                    return true;
                },
                onStopJob(jobParameters) {
                    console.log('background: service onStopJob');
                    this.jobFinished(jobParameters, false);
                    stopTimer();
                    return false;
                },
            });
        }
    }
     
    /**
     * 定期実行設定
     * @param {number} interval 時間間隔(sec)
     */
    function startTimer(interval) {
        if(interval>0 && timerid==null){
            timerid = Timer.setInterval(() => {
                const randNumber = Math.random();
                console.log(randNumber);
            }, interval*1000);
            console.log('worker: set timer to interval '+ interval*1000 + 'ms.');
        }
    }
     
    /**
     * 定期実行停止
     */
    function stopTimer() {
        if(timerid!=null){
            Timer.clearInterval(timerid);
            timerid = null;
            console.log('background: stop timer.');
        }
    } 

  3. manifestにサービスを記述します
    app/App_Resources/Android/src/main/AndroidManifest.xml
      1
      2
      3
      4
      5
    
    	<application
                :
    		<service android:name="jp.inxray.scop.BackgroundService" android:exported="false"></service>
    		<service android:name="jp.inxray.scop.BackgroundService26" android:permission="android.permission.BIND_JOB_SERVICE" android:enabled="true" android:exported="false"></service>
    	</application>

  4. webpack.configの設定
    webpack(--bundle)を使わない場合はここまでで動くのですが、NativeScript6からwebpack必須になりました。
    webpackに対応するには以下の設定が必要です。

    webpack.config.js

      1
      2
      3
      4
      5
    
        const appComponents = [
            "tns-core-modules/ui/frame",
            "tns-core-modules/ui/frame/activity",
            resolve(__dirname, "app/service/background.js"),
        ]; 
    4行目にサービスの実行ファイルを追記しています。

以上で、tns run android --bundleすると、アプリを閉じてもタスクリストから終了しても、30秒ごとにランダムな数字がコンソールにログ出力されます。

以上です。

Category: [NativeScript] - 14:15:52

私の中で「サービス」と言えばこれ(笑)



 
Last-modified: 2019-07-29 (月) 14:15:52 (492d)