zoukankan      html  css  js  c++  java
  • [记录点滴]Ionic编译过程的研究

    [记录点滴]Ionic编译过程的研究

    0x00 摘要

    之前研究Ionic编译过程的笔记,发出来做个记录。当时是因为有些图片没有拷贝到应用中,所以需要调试编译过程。

    0x01 入口

    编译的入口在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...

    0x02 执行

    以run为例,其会调用build下面的run函数 platformsandroidcordovalib un.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下面的代码 platformsandroidcordovalibcheck_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
        ];
    }
    

    选择builder

    platformsandroidcordovalibuild.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): 
    	' + apkPaths.join('
    	'));
                return {
                    apkPaths: apkPaths,
                    buildType: opts.buildType,
                    buildMethod: opts.buildMethod
                };
            });
        });
    };
    

    cordovalibuilders下面的函数 会调用具体的builder,比如ant还是gradle。

    platformsandroidcordovalibuildersuilder.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的编译调用在 platformsandroidcordovalibuildersGradleBuilder.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);
        });
    };
    

    0x03 排查拷贝文件

    关键词的查找

    { 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');
        });
    };
    

    第二步,实验添加log代码:

    cordovalib
    un.js
    module.exports.run = function(runOptions) {
    console.log("================= cordova lib run =================");
    }
    
    cordovalibprepare.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);    
    ....
    }
    

    第三步,执行看看log

    C:>ionic prepare android
    ================= cordova lib prepare =================
    ================= cordova lib handleIcons =================projectRoot: C
    ================= cordova lib prepare =================destination: C:platformsandroid
    es
    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
    
  • 相关阅读:
    Xcode9学习笔记74
    Xcode9学习笔记73
    Xcode9学习笔记72
    Xcode9学习笔记71
    【Finish】Python Day 8
    【Finish】Python Day 7
    【Finish】Python Day 6
    【Finish】Python Day 5
    【Finish】Python Day 4
    【Finish】Python Day 3
  • 原文地址:https://www.cnblogs.com/rossiXYZ/p/13196461.html
Copyright © 2011-2022 走看看