Cordova CLI源码分析(五)——添加平台

本文详细介绍了Cordova中如何通过SDK环境创建原生工程文件,包括核心函数platform、supports及call_into_create的功能与流程,展示了如何针对不同平台进行工程创建与配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

添加平台支持,其实本质是利用各平台SDK环境创建原生工程文件。所以,所有函数也是围绕这一主题展开。

入口当然是platform函数

module.exports = function platform(command, targets, callback) {

.....

};

先不看具体源码,再看其他几个函数

(1)module.exports.supports = function(project_root, name, callback) {

这个函数主要执行以下几步:

//检查传入参数

//判断平台是否支持

//获得顶层目录下platforms.jsparser参数指定的各平台解析文件

//检查各平台依赖的SDK是否存在

/**
 * Check Platform Support.
 *
 * Options:
 *
 *   - {String} `name` of the platform to test.
 *   - {Function} `callback` is triggered with the answer.
 *     - {Error} `e` null when a platform is supported otherwise describes error.
 */

module.exports.supports = function(project_root, name, callback) {
    // required parameters
    if (!name) throw new Error('requires a platform name parameter');
    if (!callback) throw new Error('requires a callback parameter');

    // check if platform exists
    var platform = platforms[name];
    if (!platform) {
        callback(new Error(util.format('"%s" platform does not exist', name)));
        return;
    }

    // look up platform meta-data parser
    var platformParser = platforms[name].parser;
    if (!platformParser) {
        callback(new Error(util.format('"%s" platform parser does not exist', name)));
        return;
    }

    // check for platform support
    platformParser.check_requirements(project_root, function(e) {
        // typecast String to Error
        e = (typeof e == 'string') ? new Error(e) : e;
        // typecast false Boolean to null
        e = (e) ? e : null;

        callback(e);
    });
};

(2)function call_into_create(target, projectRoot, cfg, id, version, callback, end) {

这个函数调用各个移动开发平台SDK环境中提供的创建原生工程文件的方法,创建工程

function call_into_create(target, projectRoot, cfg, id, version, callback, end) {
    var output = path.join(projectRoot, 'platforms', target);

    // Check if output directory already exists.
    if (fs.existsSync(output)) {
        var err = new Error('Platform "' + target + '" already exists at "' + output + '"');
        if (callback) callback(err);
        else throw err;
    } else {
        // Make sure we have minimum requirements to work with specified platform
        events.emit('log', 'Checking if platform "' + target + '" passes minimum requirements...');
        module.exports.supports(projectRoot, target, function(err) {
            if (err) {
                if (callback) callback(err);
                else throw err;
            } else {
                // Create a platform app using the ./bin/create scripts that exist in each repo.
                // Run platform's create script
                var bin = path.join(cordova_util.libDirectory, target, id, version, 'bin', 'create');
                //调用不同平台下创建工程命令
                if(target == 'wp7') bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp7', 'bin', 'create');
                if(target == 'wp8') bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp8', 'bin', 'create');
                var args = (target=='ios') ? '--arc' : '';
                var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
                var name = cfg.name();
                var command = util.format('"%s" %s "%s" "%s" "%s"', bin, args, output, pkg, name);
                events.emit('log', 'Running bin/create for platform "' + target + '" with command: "' + command + '" (output to follow)');

                shell.exec(command, {silent:true,async:true}, function(code, create_output) {
                    events.emit('log', create_output);
                    if (code > 0) {
                        var err = new Error('An error occured during creation of ' + target + ' sub-project. ' + create_output);
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        require('../cordova').prepare(target, function(err) {
                            if (err) {
                                if (callback) callback(err);
                                else throw err;
                            } else {
                                createOverrides(projectRoot, target);
                                end(); //platform add is done by now.
                                // Install all currently installed plugins into this new platform.
                                var plugins_dir = path.join(projectRoot, 'plugins');
                                var plugins = cordova_util.findPlugins(plugins_dir);
                                var parser = new platforms[target].parser(output);
                                plugins && plugins.forEach(function(plugin) {
                                    events.emit('log', 'Installing plugin "' + plugin + '" following successful platform add of ' + target);
                                    plugman.install(target, output, path.basename(plugin), plugins_dir, { www_dir: parser.staging_dir() });
                                });
                            }
                        });
                    }
                });
            }
        });
    }
}

(3)最会回到platform函数

module.exports = function platform(command, targets, callback) {
    var projectRoot = cordova_util.isCordova(process.cwd());
    //检查是否在根目录下存在.cordova目录,如果存在此目录才是cordova项目,返回此绝对路径;否则返回false

    if (!projectRoot) {
        var err = new Error('Current working directory is not a Cordova-based project.');
        if (callback) callback(err);
        else throw err;
        return;
    }

    var hooks = new hooker(projectRoot);

    if (arguments.length === 0) command = 'ls';//参数为空,默认为ls
    if (targets) {
        if (!(targets instanceof Array)) targets = [targets];//遍历targets对象是否是系统支持平台参数
        targets.forEach(function(t) {
            if (!(t in platforms)) {
                var err = new Error('Platform "' + t + '" not recognized as core cordova platform.');
                if (callback) return callback(err);
                else throw err;
            }
        });
    } else {
        if (command == 'add' || command == 'rm') {
            var err = new Error('You need to qualify `add` or `remove` with one or more platforms!');
            if (callback) return callback(err);
            else throw err;
        }
    }

    var xml = cordova_util.projectConfig(projectRoot);//根目录/www/config.xml
    var cfg = new cordova_util.config_parser(xml);//解析xml文件
    var opts = {
        platforms:targets
    };

    switch(command) {
        case 'add':
            var end = n(targets.length, function() {
                hooks.fire('after_platform_add', opts, function(err) {
                    if (err) {
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        if (callback) callback();
                    }
                });
            });
            hooks.fire('before_platform_add', opts, function(err) {
                if (err) {
                    if (callback) callback(err);
                    else throw err;
                } else {
                    var config_json = config.read(projectRoot);
                    targets.forEach(function(t) {
                        lazy_load.based_on_config(projectRoot, t, function(err) {
                            if (err) {
                                if (callback) callback(err);
                                else throw err;
                            } else {
                                if (config_json.lib && config_json.lib[t]) {
                                    call_into_create(t, projectRoot, cfg, config_json.lib[t].id, config_json.lib[t].version, callback, end);
                                } else {
                                    call_into_create(t, projectRoot, cfg, 'cordova', platforms[t].version, callback, end);
                                }
                            }
                        });
                    });
                }
            });
            break;
        case 'rm':
        case 'remove':
            var end = n(targets.length, function() {
                hooks.fire('after_platform_rm', opts, function(err) {
                    if (err) {
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        if (callback) callback();
                    }
                });
            });
            hooks.fire('before_platform_rm', opts, function(err) {
                if (err) {
                    if (callback) callback(err);
                    else throw err;
                } else {
                    targets.forEach(function(target) {
                        shell.rm('-rf', path.join(projectRoot, 'platforms', target));
                        shell.rm('-rf', path.join(cordova_util.appDir(projectRoot), 'merges', target));
                        var plugins_json = path.join(projectRoot, 'plugins', target + '.json');
                        if (fs.existsSync(plugins_json)) shell.rm(plugins_json);
                        end();
                    });
                }
            });
            break;
        case 'ls':
        case 'list':
        default:
            var platforms_on_fs = cordova_util.listPlatforms(projectRoot);
            hooks.fire('before_platform_ls', function(err) {
                if (err) {
                    if (callback) callback(err);
                    else throw err;
                } else {
                    events.emit('results', (platforms_on_fs.length ? platforms_on_fs : 'No platforms added. Use `cordova platform add <platform>`.'));
                    hooks.fire('after_platform_ls', function(err) {
                        if (err) {
                            if (callback) callback(err);
                            else throw err;
                        }
                    });
                }
            });
            break;
    }
};

结构比较简单,参数检查,然后根据不同参数执行不同动作,需要唯一说明的是,在switch函数中出现的

 var end = n(targets.length, function() {
                hooks.fire('after_platform_add', opts, function(err) {
                    if (err) {
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        if (callback) callback();
                    }
                });
            });

这个函数是使用的nodenCallbacks插件,https://npmjs.org/package/ncallbacks

官方文档解释是function that executes n times,在上面这段代码中意思就是,end函数只能被执行targets.length次,调用超过targets.length次再调用end,其内部函数也不会再被执行,其实就是限制次数,避免当平台列表中为空后还误执行



<think>好的,我需要帮助用户了解和使用Cordova命令行接口进行移动应用开发。首先,我得回顾用户提供的引用内容,确保回答准确。用户引用了几个关于Cordova命令行的内容,比如创建项目添加插件等。 首先,Cordova CLI的基础是安装和创建项目。用户需要安装Node.js和npm,然后通过npm安装Cordova。创建项目时,使用`cordova create`命令,并指定包名和项目名。例如,引用[3]提到了`cordova create hello com.wsp.helloworld helloworld`,这可以作为示例。 接下来,添加平台是关键步骤。用户需要进入项目目录,运行`cordova platform add`来添加目标平台,比如Android或iOS。这部分需要明确步骤,确保用户不会遗漏。 然后,添加插件是扩展功能的重要部分。引用[4]提到使用`cordova plugin add`来安装插件,比如InAppBrowser。这里可以举例说明常用插件,并强调插件的作用。 构建和运行项目是开发的核心步骤。用户需要知道如何构建项目并运行到模拟器或设备上。命令如`cordova build android`和`cordova run android`需要详细说明。 用户可能遇到的问题,比如环境配置或插件兼容性,也需要提及。引用[2]提到在创建项目时选择starter项目并集成Cordova,这部分可以强调项目初始化的注意事项。 最后,生成相关问题需要考虑用户可能深入的方面,比如调试、性能优化、插件开发等。这些问题需要与Cordova CLI的使用相关,帮助用户进一步学习。 确保回答结构清晰,分步骤说明,并正确引用提供的资料。同时,检查所有命令是否符合引用内容,避免错误。例如,引用[1]提到`cordova help`可以查看所有命令,这应该在常用命令部分提到。 总结回答的结构:安装、创建项目添加平台添加插件、构建运行、常用命令、常见问题、相关问题。这样用户能逐步跟随操作,顺利使用Cordova CLI进行开发。</think>### Cordova命令行接口(CLI)使用指南 Cordova CLI是用于创建、构建和管理跨平台移动应用的核心工具。以下是关键步骤和示例: #### 1. **环境准备** - 安装Node.js和npm(Cordova依赖环境) - 安装Cordova CLI: ```bash npm install -g cordova ``` #### 2. **创建项目** - 使用`cordova create`初始化项目,语法为: ```bash cordova create <目录名> <包名> <应用名> ``` 示例(引用[3]): ```bash cordova create hello com.wsp.helloworld helloworld ``` #### 3. **添加平台** - 进入项目目录后,添加目标平台(如Android/iOS): ```bash cd hello cordova platform add android ``` #### 4. **添加插件** - 通过`cordova plugin add`扩展功能(引用[4]): ```bash cordova plugin add cordova-plugin-inappbrowser ``` #### 5. **构建与运行** - 构建项目: ```bash cordova build android ``` - 运行到设备/模拟器: ```bash cordova run android ``` #### 6. **常用命令** - 查看所有命令(引用[1]): ```bash cordova help ``` - 移除平台: ```bash cordova platform remove android ``` #### 7. **调试与测试** - 浏览器实时调试(引用[2]): ```bash ionic serve # 适用于Ionic集成项目 ``` --- ### 常见问题 1. **如何解决插件兼容性问题?** 通过`cordova plugin list`检查已安装插件版本,确保与Cordova版本匹配。 2. **如何适配不同平台?** 修改`config.xml`中的配置项,例如图标、权限等。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值