中安拓也のブログ

プログラミングについて書くブログ

【Ionic(Cordova)】GradleによるAndroidビルド時のリポジトリの参照先をNexusに変更する

はじめに

Ionic(Cordova/Angular)アプリのAndroidビルドに時間がかかりすぎているせいで、Jenkinsのビルドが不安定になるという問題が発生しました。

そのため、mavenリポジトリの参照先をMaven Central リポジトリから、Nexusリポジトリに変更する対応を実施します。なお、AndroidビルドはGradleで実施していて、Nexusのリポジトリは社内向けのため認証があります。

環境

  • "cordova-android": "8.1.0",
  • "@ionic/angular": "5.1.0",
  • "@ionic/core": "5.1.0",

Cordova フックスクリプトを作成する

リポジトリの参照先をNexusに変更するには、platforms/android配下のbuild.gradleを修正する必要があります。ただし、build.gradleはビルド時に生成されるファイルであるため、手動で直接修正することはできません。

そのため、今回はCordovaフックスクリプトを作成することで、build.gradleファイルを修正します。

下記の通り、config.xml<platform name="android">配下に行を追記することで、Androidのビルド前にスクリプト(build_scripts/android-before-build.js)を呼び出すことができます。

config.xml

<platform name="android">
    <hook src="build_scripts/android-before-build.js" type="before_build" />
</platform>

続いてフックされるスクリプトを作成します。

build_scripts/android-before-build.js

/*
 * 最初に依存先を探すリポジトリをNexusに設定する。
 */
const fs = require('fs');
const path = require('path');
const async = require('async');

module.exports = context => {
  'use strict';
  const repoUrl =
    '[NexusリポジトリのURL]';
  const env = process.env;
  const gradleRepo = `maven {
     url "${repoUrl}"
     credentials {
       username "${env.NEXUS_USER}"
       password "${env.NEXUS_AUTH}"
     }
    }`;
  if (env.NEXUS_USER == null || env.NEXUS_AUTH == null) {
    return;
  }
  return new Promise((resolve, reject) => {
    const platformRoot = path.join(
      context.opts.projectRoot,
      'platforms/android'
    );

    const gradleFiles = findGradleFiles(platformRoot);

    // 最初に依存先を探すリポジトリをNexusに設定する。
    async.each(
      gradleFiles,
      function(file, callback) {
        let fileContents = fs.readFileSync(file, 'utf8');

        const insertLocations = [];
        const myRegexp = /\brepositories\s*{(.*)$/gm;
        let match = myRegexp.exec(fileContents);
        while (match != null) {
          if (match[1].indexOf(repoUrl) < 0) {
            insertLocations.push(match.index + match[0].length);
          }
          match = myRegexp.exec(fileContents);
        }

        if (insertLocations.length > 0) {
          insertLocations.reverse();
          insertLocations.forEach(location => {
            fileContents =
              fileContents.substr(0, location) +
              gradleRepo +
              fileContents.substr(location);
          });

          fs.writeFileSync(file, fileContents, 'utf8');
        }

        callback();
      },
      function(err) {
        if (err) {
          reject();
        } else {
          resolve();
        }
      }
    );
  });

  /**
   * gradleファイルのパスの一覧を返す
   *
   * @param {*} dir Androidプロジェクトのパス
   * @return {*} gradleファイルのパスの一覧
   */
  function findGradleFiles(dir) {
    let results = [];
    const list = fs.readdirSync(dir);
    list.forEach(fileName => {
      const filePath = path.join(dir, fileName);
      const stat = fs.statSync(filePath);
      if (stat && stat.isDirectory()) {
        results = results.concat(findGradleFiles(filePath));
      } else if (path.extname(filePath) === '.gradle') {
        results.push(filePath);
      }
    });
    return results;
  }
};

上記のスクリプトを実行するとbuild.gradleがこのようになります。

スクリプト実行前のbuild.gradle

f:id:l08084:20201210175410p:plain
スクリプト実行前のbuild.gradle

スクリプト実行後のbuild.gradle

f:id:l08084:20201210175727p:plain
スクリプト実行後のbuild.gradle

スクリプト実行前には、mavenCentralがリポジトリ探索の優先順位の一番だったのに、スクリプト実行後には、Nexusのリポジトリが探索の優先順位の一番になっていることがわかります。

スクリプトの処理内容について説明します。

上記のスクリプトは、repositoriesという文字列の後に下記の文言を追加するというものです。

    maven {
        url [NexusリポジトリURL]
        credentials {
          username [Nexusリポジトリ アカウントID]
          password [Nexusリポジトリ パスワード]
        }
    }

こうすることで、認証付きのNexusリポジトリにアクセスできるようになります。

参考記事

フック ガイド - Apache Cordova

android - Specify different repositories when using Cordova gradle wrapper - Stack Overflow

第8章 依存関係管理の基本

[CB-9704] Apache Cordova 5 does not support using a custom nexus repository for android builds - ASF JIRA

gradle + bitbucket + 社内向け (認証あり) maven リポジトリの設定手順 - Qiita

Where to put Gradle configuration (i.e. credentials) that should not be committed? - Stack Overflow

正規表現(RegExp) - とほほのWWW入門