[android] added module

This commit is contained in:
2018-05-08 18:05:29 +03:00
parent 331d687f66
commit 4ed7fb3a02
4 changed files with 214 additions and 41 deletions

127
haxetool/android.js Normal file
View File

@@ -0,0 +1,127 @@
const fs = require('fs');
const exec = require('./exec');
const through = require('through2');
const Sdk = require('./sdk');
const Env = require('./env');
class Android extends Sdk {
constructor(version) {
super(Android.ID, version || Android.VERSION);
}
get prepared() {
try {
return fs.existsSync(`${this.path}/platform-tools/adb`);
} catch (e) {
return false;
}
}
get link() {
const system = Sdk.System.isWindows ? 'windows' : Sdk.System.isLinux ? 'linux' : null;
if (!system) throw 'Unsupported system';
//return `https://dl.google.com/android/repository/sdk-tools-${system}-${this.version}.zip`;
return `https://dl.google.com/android/repository/tools_r${this.version}-${system}.zip`;
}
prepare() {
return this.prepared ? Promise.resolve() : super.prepare(0).then(() => {
return this.sdkmanager([
'ndk-bundle',
'tools',
'platform-tools',
'build-tools;27.0.3',
'platforms;android-27',
]);
});
}
sdkmanager(packages) {
const androidBin = `${this.path}/tools/bin/sdkmanager`;
if (fs.existsSync(androidBin)) {
fs.chmodSync(androidBin, 0o755);
}
const yes = '(while sleep 3; do echo "y"; done)';
return exec('.', [yes, '|', androidBin].concat(packages.map(name => `"${name}"`)).join(' '));
}
activate() {
Env.set('ANDROID_HOME', this.path);
}
adb(args) {
const adbBin = `${this.path}/platform-tools/adb`;
return exec('.', [adbBin].concat(args).join(' ')).then(data => {
for (let line of data.stderr.split('\n')) {
if (line.indexOf('Error') > -1) {
throw line;
}
}
});
}
aapt(args) {
let buildToolsVersion = null;
fs.readdirSync(`${this.path}/build-tools`).forEach(file => {
buildToolsVersion = file;
});
const aaptBin = `${this.path}/build-tools/${buildToolsVersion}/aapt`;
return exec('.', [aaptBin].concat(args).join(' '));
}
apk() {
const self = this;
return through.obj(function(file, enc, callback) {
self.aapt(['l', '-a', file.path]).then(data => {
let activity = false;
for (let line of data.stdout.split('\n')) {
if (line.indexOf('package') > -1) {
const value = /"(.*?)"/.exec(line);
if (value) file.package = value[1]
}
if (line.indexOf('activity') > -1) {
activity = true;
}
if (activity && line.indexOf('name') > -1) {
const value = /"(.*?)"/.exec(line);
if (value) {
file.activity = value[1];
activity = false;
}
}
}
this.push(file);
callback();
});
});
}
install() {
const self = this;
return through.obj(function(file, enc, callback) {
self.adb(['install', '-r', file.path]).then(() => {
this.push(file);
callback();
});
});
}
start() {
const self = this;
return through.obj((file, enc, callback) => {
const name = `${file.package}/${file.activity}`;
self.adb(['shell', 'am', 'start', '-n', name]).then(() => callback());
});
}
}
Android.ID = 'android';
Android.VERSION_25_2_3 = '25.2.3';
Android.VERSION_3859397 = '3859397';
Android.VERSION = Android.VERSION_25_2_3;
module.exports = Android;

View File

@@ -92,7 +92,11 @@ class Haxe extends Sdk {
} }
const target = path.resolve(buildDir, platform, 'bin'); const target = path.resolve(buildDir, platform, 'bin');
fse.emptyDirSync(target); fse.emptyDirSync(target);
return this.haxelib(args).then(() => vfs.src(`${target}/**/*`)); const result = {
'android': 'app/build/outputs/apk/*.apk',
'flash': '*.swf',
}[platform] || '**/*';
return this.haxelib(args).then(() => vfs.src(`${target}/${result}`));
} }
build(platform, config, debug=false) { build(platform, config, debug=false) {
@@ -121,7 +125,7 @@ class Haxe extends Sdk {
args.push('-debug'); args.push('-debug');
} }
const target = path.resolve(buildDir, platform, 'bin'); const target = path.resolve(buildDir, platform, 'bin');
fse.emptyDirSync(target) fse.emptyDirSync(target);
for (const asset of config.assets) { for (const asset of config.assets) {
fse.copySync(asset, path.join(target, asset.split(path.sep).pop())); fse.copySync(asset, path.join(target, asset.split(path.sep).pop()));
} }

View File

@@ -5,11 +5,13 @@ const fs = require('fs');
const fse = require('fs-extra'); const fse = require('fs-extra');
const Haxe = require('./haxe'); const Haxe = require('./haxe');
const FlashPlayer = require('./flashplayer'); const FlashPlayer = require('./flashplayer');
const Android = require('./android');
const Neko = require('./neko'); const Neko = require('./neko');
const debug = require('./debug'); const debug = require('./debug');
const webserver = require('gulp-webserver'); const webserver = require('gulp-webserver');
const run = require('../run/index'); const run = require('../run/index');
const tail = require('./tail'); const tail = require('./tail');
const exec = require('./exec');
const deb = require('gulp-debian'); const deb = require('gulp-debian');
const {BuildSystem, Platform, Config} = require('./core'); const {BuildSystem, Platform, Config} = require('./core');
const vfs = require('vinyl-fs'); const vfs = require('vinyl-fs');
@@ -36,6 +38,14 @@ class Target {
this.target = 'target'; this.target = 'target';
} }
prepare() {
return Promise.resolve();
}
call() {
throw 'Not Implemented';
}
get targetPath() { get targetPath() {
return path.resolve(this.target, this.config.name, this.platform); return path.resolve(this.target, this.config.name, this.platform);
} }
@@ -52,14 +62,6 @@ class Builder extends Target {
this.debug = debug; this.debug = debug;
} }
prepare() {
return Promise.resolve();
}
call() {
throw 'Not Implemented';
}
static register(buildSystem, builder) { static register(buildSystem, builder) {
Builder.factory[buildSystem] = builder; Builder.factory[buildSystem] = builder;
} }
@@ -79,15 +81,26 @@ class HaxeBuilder extends Builder {
constructor(config, platform, buildSystem, debug) { constructor(config, platform, buildSystem, debug) {
super(config, platform, buildSystem, debug); super(config, platform, buildSystem, debug);
this.haxe = new Haxe(); this.haxe = new Haxe();
this.android = new Android();
} }
prepare() { prepare() {
let result = this.haxe.prepare().then(() => this.haxe.install(this.config.libs)); let result = this.haxe.prepare().then(() => this.haxe.install(this.config.libs));
/*if (this.buildSystem === BuildSystem.OPENFL) { if (this.buildSystem === BuildSystem.OPENFL) {
if (this.platform === Platform.ANDROID) {
result = result.then(() => this.android.prepare()).then(() => this.android.activate());
}
result = result.then(() => { result = result.then(() => {
return this.haxe.haxelib(['run', 'openfl', 'setup', this.platform]); return exec('.', [
'echo',
`"${this.android.path}"`,
`"${this.android.path + '/ndk-bundle'}"`,
'|',
this.haxe.haxelibBin, 'run', 'openfl', 'setup', this.platform,
].join(' '));
//return this.haxe.haxelib(['echo'].concat(answers.map(item => `"${item}"`)).concat(['|', 'run', 'openfl', 'setup', this.platform]));
}); });
}*/ }
return result; return result;
} }
@@ -112,20 +125,17 @@ Builder.register(BuildSystem.OPENFL, HaxeBuilder);
*/ */
class Packer extends Target { class Packer extends Target {
prepare() {
return Promise.resolve();
}
call() { call() {
throw 'Not Implemented'; throw 'Not Implemented';
} }
static register(platform, packer) { static register(platform, name, packer) {
Packer.factory[platform] = packer; if (!Packer.factory[platform]) Packer.factory[platform] = {};
Packer.factory[platform][name] = packer;
} }
static new(config, platform) { static new(config, platform, name) {
return new Packer.factory[platform](config); return new Packer.factory[platform][name](config);
} }
} }
@@ -134,7 +144,7 @@ Packer.factory = {};
/** /**
* *
*/ */
class FlashPacker extends Packer { class FlashHTMLPacker extends Packer {
constructor(config) { constructor(config) {
super(config, Platform.FLASH); super(config, Platform.FLASH);
@@ -150,12 +160,14 @@ class FlashPacker extends Packer {
} }
} }
Packer.register(Platform.FLASH, FlashPacker); FlashHTMLPacker.NAME = 'html';
Packer.register(Platform.FLASH, FlashHTMLPacker.NAME, FlashHTMLPacker);
/** /**
* *
*/ */
class LinuxPacker extends Packer { class LinuxDEBPacker extends Packer {
constructor(config) { constructor(config) {
super(config, Platform.LINUX); super(config, Platform.LINUX);
@@ -192,7 +204,9 @@ class LinuxPacker extends Packer {
} }
} }
Packer.register(Platform.LINUX, LinuxPacker); LinuxDEBPacker.NAME = 'deb';
Packer.register(Platform.LINUX, LinuxDEBPacker.NAME, LinuxDEBPacker);
/** /**
* *
@@ -204,14 +218,6 @@ class Runner extends Target {
this.debug = debug; this.debug = debug;
} }
prepare() {
return Promise.resolve();
}
call() {
throw 'Not Implemented';
}
log(stream) { log(stream) {
return stream return stream
.pipe(tail(debug.log)) .pipe(tail(debug.log))
@@ -319,6 +325,33 @@ class NekoRunner extends Runner {
Runner.register(Platform.NEKO, NekoRunner); Runner.register(Platform.NEKO, NekoRunner);
/**
*
*/
class AndroidRunner extends Runner {
constructor(config, debug) {
super(config, Platform.ANDROID, debug);
this.android = new Android();
}
prepare() {
return this.android.prepare();
}
call() {
const target = this.targetPath;
const filename = path.resolve(target, this.config.meta.filename+'-debug.apk');
console.log(filename);
return gulp.src(filename)
.pipe(this.android.apk())
.pipe(this.android.install())
.pipe(this.android.start());
}
}
Runner.register(Platform.ANDROID, AndroidRunner);
/** /**
* *
@@ -340,16 +373,20 @@ class Project {
return tasks; return tasks;
} }
run(platform) { run(platform, debug) {
const runner = Runner.new(this.config, platform, debug); const runner = Runner.new(this.config, platform, debug);
return this.build(platform, debug).concat([ return [
runner.prepare.bind(runner), runner.prepare.bind(runner),
runner.call.bind(runner), runner.call.bind(runner),
]); ];
} }
pack(platform) { test(platform) {
const packer = Packer.new(this.config, platform); return this.build(platform, debug).concat(this.run(platform, debug));
}
pack(platform, name) {
const packer = Packer.new(this.config, platform, name);
return [ return [
packer.prepare.bind(packer), packer.prepare.bind(packer),
packer.call.bind(packer), packer.call.bind(packer),
@@ -360,9 +397,14 @@ class Project {
const _gulp = (external_gulp || gulp); const _gulp = (external_gulp || gulp);
for (const platform of this.platforms) { for (const platform of this.platforms) {
module.exports[`${this.config.name}:${platform}:build`] = _gulp.series(this.build(platform)); module.exports[`${this.config.name}:${platform}:build`] = _gulp.series(this.build(platform));
module.exports[`${this.config.name}:${platform}:run`] = _gulp.series(this.run(platform)); if (Runner.factory[platform]) {
module.exports[`${this.config.name}:${platform}:run`] = _gulp.series(this.run(platform));
module.exports[`${this.config.name}:${platform}:test`] = _gulp.series(this.test(platform));
}
if (Packer.factory[platform]) { if (Packer.factory[platform]) {
module.exports[`${this.config.name}:${platform}:pack`] = _gulp.series(this.pack(platform)); for (const name of Object.keys(Packer.factory[platform])) {
module.exports[`${this.config.name}:${platform}:${name}`] = _gulp.series(this.pack(platform, name));
}
} }
} }
return this; return this;

View File

@@ -85,7 +85,7 @@ class Sdk {
stream = stream.on('downloadProgress', (p) => bar.update(p.percent)); stream = stream.on('downloadProgress', (p) => bar.update(p.percent));
if (this.link.endsWith('.zip')) { if (this.link.endsWith('.zip')) {
stream = stream.pipe(unzip.Parse()).on('entry', (entry) => { stream = stream.pipe(unzip.Parse()).on('entry', (entry) => {
const filePath = entry.path.split('/').slice(1).join(path.sep); const filePath = entry.path.split('/').slice(strip).join(path.sep);
if (filePath.length > 0) { if (filePath.length > 0) {
if (entry.type === 'Directory') { if (entry.type === 'Directory') {
fse.ensureDirSync(path.join(this.path, path.normalize(filePath))); fse.ensureDirSync(path.join(this.path, path.normalize(filePath)));