[android] added module
This commit is contained in:
127
haxetool/android.js
Normal file
127
haxetool/android.js
Normal 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;
|
||||||
@@ -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()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
if (Runner.factory[platform]) {
|
||||||
module.exports[`${this.config.name}:${platform}:run`] = _gulp.series(this.run(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;
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
|||||||
Reference in New Issue
Block a user