[記録点滴]Ionicコンパイルプロセスの研究

10232 ワード

[記録点滴]Ionicコンパイルプロセスの研究
0 x 00サマリ
以前、Ionicのコンパイルプロセスを研究していたノートを、記録に出しました.当時、一部の画像がアプリケーションにコピーされていなかったため、コンパイルプロセスをデバッグする必要があった.
0 x 01エントリ
コンパイルされたエントリはplatformsandroidcordovaで、具体的には次のスクリプトファイルです.
android_sdk_version  build.bat       clean         lib      loggingHelper.js  run.bat
Api.js               check_reqs      clean.bat     log      node_modules      version
build                check_reqs.bat  defaults.xml  log.bat  run               version.bat

対応するコマンドはionic run/build/clean...
0 x 02実行
runを例にとると、buildの下のrun関数platformsandroidcordovalibrunが呼び出されます.js
build = require('./build'),

module.exports.run = function(runOptions) {
    return Q()
      ...
        return build.run.call(self, runOptions, resolvedTarget) 
      ...
	}
};

buildを例にとるとbuild.batはbuildファイルを直接呼び出し、コンパイルします.
実際に実行
buildが本当に実行するコマンドはここにあります.
new Api().build(buildOpts)

./android/cordova/Api.js:Api.prototype.prepare = function (cordovaProject, prepareOptions) {
./android/cordova/Api.js:    return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
./android/cordova/Api.js:    return require('./lib/prepare').clean.call(self, cleanOptions);

Apiでjsではbuildコードは次のとおりです.
Api.prototype.build = function (buildOptions) {
    var self = this;
    return require('./lib/check_reqs').run()
    .then(function () {
        return require('./lib/build').run.call(self, buildOptions);
    })
    .then(function (buildResults) {
        // Cast build result to array of build artifacts
        return buildResults.apkPaths.map(function (apkPath) {
            return {
                buildType: buildResults.buildType,
                buildMethod: buildResults.buildMethod,
                path: apkPath,
                type: 'apk'
            };
        });
    });
};

Check
cordovalibの下のコードplatforms\android\cordova\lib\check_reqs.jsは様々なcheckをしています.
module.exports.check_all = function() {
    var requirements = [
        new Requirement('java', 'Java JDK'),
        new Requirement('androidSdk', 'Android SDK'),
        new Requirement('androidTarget', 'Android target'),
        new Requirement('gradle', 'Gradle')
    ];

    var checkFns = [
        this.check_java,
        this.check_android,
        this.check_android_target,
        this.check_gradle
    ];
}

ビルダーの選択platforms\android\cordova\lib\build.js builderが選択され、そのbuild関数が呼び出されます.
var builders = require('./builders/builders');

module.exports.run = function(options, optResolvedTarget) {
    var opts = parseOpts(options, optResolvedTarget, this.root);
    var builder = builders.getBuilder(opts.buildMethod);
    return builder.prepEnv(opts)
    .then(function() {
        if (opts.prepEnv) {
            events.emit('verbose', 'Build file successfully prepared.');
            return;
        }
        return builder.build(opts)
        .then(function() {
            var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
            events.emit('log', 'Built the following apk(s): 
\t' + apkPaths.join('
\t')); return { apkPaths: apkPaths, buildType: opts.buildType, buildMethod: opts.buildMethod }; }); }); };

cordovalibbuildersの下の関数はantやgradleなどの特定のbuilderを呼び出します.
platforms\android\cordova\lib\builders\builder.jsは具体的にどんなbuilderを選びますか.
var knownBuilders = {
    ant: 'AntBuilder',
    gradle: 'GradleBuilder',
    none: 'GenericBuilder'
};

module.exports.getBuilder = function (builderType, projectRoot) {
    if (!knownBuilders[builderType])
        throw new CordovaError('Builder ' + builderType + ' is not supported.');
    try {
        var Builder = require('./' + knownBuilders[builderType]);
        return new Builder(projectRoot);
    } catch (err) {
        throw new CordovaError('Failed to instantiate ' + knownBuilders[builderType] + ' builder: ' + err);
    }
};

GradleBuilder
Gradleのコンパイルコールはplatforms\android\cordova\lib\builders\GradleBuilder.js
GradleBuilder.prototype.build = function(opts) {
    var wrapper = path.join(this.root, 'gradlew');
    var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);

    return spawn(wrapper, args, {stdio: 'pipe'})
    .progress(function (stdio){
        if (stdio.stderr) {
            var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
            if (suppressThisLine) {
                return;
            }
            process.stderr.write(stdio.stderr);
        } else {
            process.stdout.write(stdio.stdout);
        }
    }).catch(function (error) {
        if (error.toString().indexOf('failed to find target with hash string') >= 0) {
            return check_reqs.check_android_target(error).then(function() {
                // If due to some odd reason - check_android_target succeeds
                // we should still fail here.
                return Q.reject(error);
            });
        }
        return Q.reject(error);
    });
};

0 x 03コピーファイルの照合
キーワードの検索
{ platforms }  ? find -type f | xargs grep -w "shell.cp"
./android/cordova/lib/builders/GradleBuilder.js:            shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
./android/cordova/lib/builders/GradleBuilder.js:            shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
./android/cordova/lib/builders/GradleBuilder.js:            shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
./android/cordova/lib/builders/GradleBuilder.js:        shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
./android/cordova/lib/pluginHandlers.js:        shell.cp('-Rf', src+'/*', dest);
./android/cordova/lib/pluginHandlers.js:        shell.cp('-f', src, dest);
./android/cordova/lib/prepare.js:    shell.cp('-f', locations.defaultConfigXml, locations.configXml);
./android/cordova/node_modules/cordova-common/src/FileUpdater.js:                shell.cp("-f", sourceFullPath, targetFullPath);
./android/cordova/node_modules/cordova-common/src/FileUpdater.js:                shell.cp("-f", sourceFullPath, targetFullPath);
./android/cordova/node_modules/cordova-common/src/FileUpdater.js:                    shell.cp("-f", sourceFullPath, targetFullPath);
{ platforms }  ? find -type f | xargs grep -w mergeAndUpdateDir
./android/cordova/lib/prepare.js:    FileUpdater.mergeAndUpdateDir(
./android/cordova/lib/prepare.js:    // No source paths are specified, so mergeAndUpdateDir() will clear the target directory.
./android/cordova/lib/prepare.js:    FileUpdater.mergeAndUpdateDir(
./android/cordova/node_modules/cordova-common/src/FileUpdater.js:function mergeAndUpdateDir(sourceDirs, targetDir, options, log) {
./android/cordova/node_modules/cordova-common/src/FileUpdater.js:    mergeAndUpdateDir: mergeAndUpdateDir

最初のステップは、ファイルのコピーが正しいかどうかを見て、初歩的な疑いはここにあります.ここはjsファイルばかりなのでconsole.log()などの関数はlogを印刷し、コンパイルプロセスをファイルに入力して見ます.例えばionic build android>logです.txt,コマンド実行が完了したらlogを見る.txtファイルのlog
./android/cordova/lib/prepare.js

module.exports.prepare = function (cordovaProject, options) {
    var self = this;
    var platformResourcesDir = path.relative(cordovaProject.root, path.join(this.locations.root, 'res'));
    
    --------   platformResourcesDir,          

// Update own www dir with project's www assets and plugins' assets and js-files
return Q.when(updateWww(cordovaProject, this.locations))
.then(function () {
    // update project according to config.xml changes.
    return updateProjectAccordingTo(self._config, self.locations);
})
.then(function () {

  -------------              ,       ,  updateIcons      
  
        updateIcons(cordovaProject, platformResourcesDir);
        updateSplashes(cordovaProject, platformResourcesDir);
    })
    .then(function () {
        events.emit('verbose', 'Prepared android project successfully');
    });
};

ステップ2では、logコードを実験的に追加します.
cordova\lib\run.js
module.exports.run = function(runOptions) {
console.log("================= cordova lib run =================");
}

cordova\lib\prepare.js
module.exports.prepare = function (cordovaProject) {
console.log("================= cordova lib prepare =================");
.....
    var projectRoot = path.dirname(projectConfig.path);
    var destination = path.join(platformRoot, 'res');
        console.log("================= cordova lib handleIcons =================projectRoot: " + projectRoot);
        console.log("================= cordova lib prepare =================destination: " + destination);    
....
}

3つ目はlogを見てみましょう
C:\>ionic prepare android
================= cordova lib prepare =================
================= cordova lib handleIcons =================projectRoot: C
================= cordova lib prepare =================destination: C:\platforms\android\res
Running command: "C:\Program Files
odejs
ode.exe" add to body class: platform-android will push strings array {"name":"lang","titles":["English (US)","English (UK)"], "values":["en-us","en-gb"]} android preferences file was successfully generated C:\>ionic build android ================= cordova lib prepare ================= ================= cordova lib handleIcons =================projectRoot: BUILD SUCCESSFUL Total time: 19.631 secs