Skip to content

Commit

Permalink
all: allow + document setting defaults at comptime (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
larpon authored Oct 13, 2024
1 parent 25a37bc commit 5725aea
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 34 deletions.
86 changes: 62 additions & 24 deletions android/package.v
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import vab.android.env
import vab.android.sdk
import vab.android.util

pub const default_app_name = 'V Test App'
pub const default_package_id = 'io.v.android'
pub const default_activity_name = 'VActivity'
pub const default_package_format = 'apk'
pub const default_min_sdk_version = 21
pub const default_app_name = $d('vab:default_app_name', 'V Test App')
pub const default_package_id = $d('vab:default_package_id', 'io.v.android')
pub const default_activity_name = $d('vab:default_activity_name', 'VActivity')
pub const default_package_format = $d('vab:default_package_format', 'apk')
pub const default_min_sdk_version = int($d('vab:default_min_sdk_version', 21))
pub const default_base_files_path = get_default_base_files_path()
pub const supported_package_formats = ['apk', 'aab']
pub const supported_lib_folders = ['armeabi', 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
Expand Down Expand Up @@ -52,6 +52,10 @@ pub:
keystore Keystore
base_files string = default_base_files_path
overrides_path string // Path to user provided files that will override `base_files`. `java` (and later `kotlin` TODO) subdirs are recognized
prepare_base_fn fn (PackageOptions) !PackageBase = prepare_package_base // function used to prepare package base files
// Defaults (allows for runtime redefinition)
default_package_id string // Reserved for defining the default package_id at runtime
default_activity_name string // Reserved for defining the default activity_name at runtime
}

// verbose prints `msg` to STDOUT if `PackageOptions.verbosity` level is >= `verbosity_level`.
Expand All @@ -62,6 +66,10 @@ pub fn (po &PackageOptions) verbose(verbosity_level int, msg string) {
}

fn get_default_base_files_path() string {
user_default_base_files_path := $d('vab:default_base_files_path', '')
if user_default_base_files_path != '' {
return user_default_base_files_path
}
// Look next to the executable
mut path := os.join_path(os.dir(os.real_path(os.executable())), 'platforms', 'android')
if os.is_dir(path) {
Expand All @@ -87,9 +95,8 @@ pub fn package(opt PackageOptions) ! {
Please consult the Android documentation for details:
https://developer.android.com/studio/build/application-id')
}
if opt.is_prod && opt.package_id == default_package_id {
return error('${error_tag}: Package id "${opt.package_id}" is used by the V team.
Please do not deploy to app stores using package id "${default_package_id}".')
if opt.is_prod {
ensure_no_developer_team_package_id(opt)!
}
// Build APK
match opt.format {
Expand Down Expand Up @@ -159,7 +166,9 @@ fn package_apk(opt PackageOptions) ! {

// Prepare and modify package skeleton shipped with vab
// Copy assets etc.
package_path, assets_path := prepare_base(opt)
package_base := opt.prepare_base_fn(opt)!
package_path := package_base.package_path
assets_path := package_base.assets_path

output_fn := os.file_name(opt.output_file).replace(os.file_ext(opt.output_file), '')
tmp_product := os.join_path(opt.work_dir, '${output_fn}.apk')
Expand Down Expand Up @@ -507,7 +516,11 @@ fn package_aab(opt PackageOptions) ! {
bundletool := env.bundletool() // Run with "java -jar ..."
aapt2 := env.aapt2()

package_path, assets_path := prepare_base(opt)
// Prepare and modify package skeleton shipped with vab
// Copy assets etc.
package_base := opt.prepare_base_fn(opt)!
package_path := package_base.package_path
assets_path := package_base.assets_path

output_fn := os.file_name(opt.output_file).replace(os.file_ext(opt.output_file), '')
tmp_product := os.join_path(opt.work_dir, '${output_fn}.aab')
Expand Down Expand Up @@ -895,7 +908,36 @@ fn package_aab(opt PackageOptions) ! {
}
}

fn prepare_base(opt PackageOptions) (string, string) {
// ensure_no_developer_team_package_id returns an error if the `opt.package_id` is the
// same as `opt.default_package_id` or the same package_id domain as `android.default_package_id`.
pub fn ensure_no_developer_team_package_id(opt PackageOptions) ! {
is_default_pkg_id := opt.package_id == opt.default_package_id
if is_default_pkg_id || opt.package_id.starts_with(default_package_id) {
if opt.package_id.starts_with(default_package_id) {
return error('Do not deploy to app stores using the default package id namespace ("${default_package_id}.*")\nYou can set your own package ID with the --package-id flag')
} else {
return error('Do not deploy to app stores using the default package id "${opt.default_package_id}"\nYou can set your own package ID with the --package-id flag')
}
}
}

pub struct PackageBase {
pub:
package_path string // Path to the base setup
assets_path string // Path to assets
}

// prepare_package_base prepares and modifies a package skeleton and returns the paths to them.
// A "package skeleton" is a special structure of directories and files that `vab`'s
// packaging step use to make the final APK or AAB package.
// prepare_package_base is run before Java tooling does the actual packaging.
//
// Preparing includes operations such as:
// * Creating the directory structures that are returned
// * Modifying template files, like `AndroidManifest.xml` or the Java Activity
// * Moving files into place
// * Copy assets to a location where `vab` can pick them up
fn prepare_package_base(opt PackageOptions) !PackageBase {
format := match opt.format {
.apk {
'apk'
Expand Down Expand Up @@ -956,23 +998,15 @@ fn prepare_base(opt PackageOptions) (string, string) {

opt.verbose(1, 'Modifying base files...')

is_default_pkg_id := opt.package_id == default_package_id
if opt.is_prod && (is_default_pkg_id || opt.package_id.starts_with(default_package_id)) {
if opt.package_id.starts_with(default_package_id) {
panic('Do not deploy to app stores using the default V package id namespace "${default_package_id}"\nYou can set your own package ID with the --package-id flag')
} else {
panic('Do not deploy to app stores using the default V package id "${default_package_id}"\nYou can set your own package ID with the --package-id flag')
}
}
pkg_id_split := opt.package_id.split('.')
package_id_path := pkg_id_split.join(os.path_separator)
os.mkdir_all(os.join_path(package_path, 'src', package_id_path)) or { panic(err) }

default_pkg_id_split := default_package_id.split('.')
default_pkg_id_split := opt.default_package_id.split('.')
default_pkg_id_path := default_pkg_id_split.join(os.path_separator)

native_activity_path := os.join_path(package_path, 'src', default_pkg_id_path)
activity_file_name := default_activity_name + '.java'
activity_file_name := opt.default_activity_name + '.java'
native_activity_file := os.join_path(native_activity_path, activity_file_name)
$if debug {
eprintln('Native activity file: "${native_activity_file}"')
Expand All @@ -985,7 +1019,7 @@ fn prepare_base(opt PackageOptions) (string, string) {
if !is_override {
// Change package id in template
// r'.*package\s+(io.v.android).*'
mut re := regex.regex_opt(r'.*package\s+(' + default_package_id + r');') or {
mut re := regex.regex_opt(r'.*package\s+(' + opt.default_package_id + r');') or {
panic(err)
}
mut start, _ := re.match_string(java_src)
Expand Down Expand Up @@ -1018,7 +1052,7 @@ fn prepare_base(opt PackageOptions) (string, string) {
java_src) or { panic(err) }

// Remove left-overs from vab's copied skeleton
if opt.package_id != default_package_id {
if opt.package_id != opt.default_package_id {
os.rm(native_activity_file) or { panic(err) }
mut v_default_package_id := default_pkg_id_split.clone()
for i := v_default_package_id.len - 1; i >= 0; i-- {
Expand Down Expand Up @@ -1173,6 +1207,7 @@ fn prepare_base(opt PackageOptions) (string, string) {

opt.verbose(1, 'Copying assets...')

is_default_pkg_id := opt.package_id == opt.default_package_id
if !is_default_pkg_id && os.is_file(opt.icon) && os.file_ext(opt.icon) == '.png' {
icon_path := os.join_path(package_path, 'res', 'mipmap')
paths.ensure(icon_path) or { panic(err) }
Expand Down Expand Up @@ -1250,7 +1285,10 @@ fn prepare_base(opt PackageOptions) (string, string) {
}
}
}
return package_path, assets_path
return PackageBase{
package_path: package_path
assets_path: assets_path
}
}

pub fn is_valid_package_id(id string) ! {
Expand Down
27 changes: 18 additions & 9 deletions cli/options.v
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,23 @@ pub:
screenshot_delay f64 @[xdoc: 'Wait for this amount of seconds before taking screenshot']
screenshot_on_log string @[xdoc: 'Wait for this string to appear in the device log before taking a screenshot']
screenshot_on_log_timeout f64 = -1.0 @[xdoc: 'Timeout after this amount of seconds if --screenshot-on-log string is not detected']
// Defaults (allows for runtime redefinition)
default_package_id string = android.default_package_id @[ignore] // Reserved for defining the default package_id at runtime
default_activity_name string = android.default_activity_name @[ignore] // Reserved for defining the default activity_name at runtime
pub mut:
// I/O
input string @[tail] // NOTE: vab also supports passing input as *first* argument
output string @[short: o; xdoc: 'Path to output (dir/file)']
additional_args []string @[ignore] // additional_args collects arguments (*not* flags) that could not be parsed
// App essentials
app_name string = android.default_app_name @[long: name; xdoc: 'Pretty app name']
icon string @[xdoc: 'App icon']
package_id string = android.default_package_id @[xdoc: 'App package ID (e.g. "org.company.app")']
activity_name string @[xdoc: 'The name of the main activity (e.g. "VActivity")']
package_format string = android.default_package_format @[long: package; xdoc: 'App package format (.apk/.aab)']
package_overrides_path string @[long: 'package-overrides'; xdoc: 'Package file overrides path (e.g. "/tmp/java")']
icon string @[xdoc: 'App icon']
app_name string = android.default_app_name @[long: name; xdoc: 'Pretty app name']
package_format string = android.default_package_format @[long: package; xdoc: 'App package format (.apk/.aab)']
// "VIP" fields. The contents of these needs to match several things thoughout
// the project being built. This includes matches in Java sources - the fields are also needed for launching.
// See also: default_package_id, default_activity_name above and `ensure_launch_fields/0`.
package_id string = android.default_package_id @[xdoc: 'App package ID (e.g. "org.company.app")']
activity_name string @[xdoc: 'The name of the main activity (e.g. "MyActivity")']
// Build and packaging
archs []string = android.default_archs @[ignore] // Compile for these archs. (parsed specially to support "arch,arch,arch")
is_prod bool @[ignore] // Parsed and inferred from V specific flags
Expand All @@ -66,6 +71,7 @@ pub mut:
keystore_alias string @[xdoc: 'Use this keystore alias from the keystore file to sign the package']
keystore_password string @[ignore] // Resolved at runtime via env var see: Options.resolve()
keystore_alias_password string @[ignore] // Resolved at runtime via env var see: Options.resolve()
package_overrides_path string @[long: 'package-overrides'; xdoc: 'Package file overrides path (e.g. "/tmp/java")']
// Build specifics
build_tools string @[xdoc: 'Version of build-tools to use (--list-build-tools)']
api_level string @[long: 'api'; xdoc: 'Android API level to use (--list-apis)']
Expand Down Expand Up @@ -442,7 +448,7 @@ pub fn (mut opt Options) extend_from_dot_vab() {
opt.app_name = vab_app_name
}
}
if opt.package_id == android.default_package_id && dot_vab.contains('package_id:') {
if opt.package_id == opt.default_package_id && dot_vab.contains('package_id:') {
vab_package_id := dot_vab.all_after('package_id:').all_before('\n').replace("'",
'').replace('"', '').trim(' ')
if vab_package_id != '' {
Expand Down Expand Up @@ -516,10 +522,10 @@ pub fn (mut opt Options) extend_from_dot_vab() {
pub fn (mut opt Options) ensure_launch_fields() {
// If no package id or activity name has set, use the defaults
if opt.package_id == '' {
opt.package_id = android.default_package_id
opt.package_id = opt.default_package_id
}
if opt.activity_name == '' {
opt.activity_name = android.default_activity_name
opt.activity_name = opt.default_activity_name
}
}

Expand Down Expand Up @@ -909,6 +915,9 @@ pub fn (opt &Options) as_android_package_options() android.PackageOptions {
libs_extra: opt.libs_extra
output_file: opt.output
overrides_path: opt.package_overrides_path
// Transfer defaults
default_package_id: opt.default_package_id
default_activity_name: opt.default_activity_name
}
return pck_opt
}
Expand Down
15 changes: 15 additions & 0 deletions docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Welcome - and have a productive time using V and `vab`!
- [Introduction](#introduction)
- [Developing `vab`](#developing-vab)
- [The V to Android App Development Cycle](#the-v-to-android-app-development-cycle)
- [Tweaking defaults at compile time](#tweaking-defaults-at-compile-time)
- [Using `vab` from the command line](#using-vab-from-the-command-line)
- [Using `vab` programmatically](#using-vab-programmatically)
- [Examples](#examples)
Expand Down Expand Up @@ -90,6 +91,20 @@ needed for the Android app to be able to start on the device OS.

The developer is expected to take care of bullet point `1.` while `vab` will help cover the rest.

# Tweaking defaults at compile time

`vab` tries to strike a balance and be sane and fair about what default values are
used. Should the defaults not fit your daily use they can be tweaked via V's
powerful compile-time defines (`-d ident=value`).

The following is a list of values that can be tweaked at compile time:
* `default_app_name` via `-d vab:default_app_name='V Test App'`
* `default_package_id` via `-d vab:default_package_id='io.v.android'`
* `default_activity_name` via `-d vab:default_activity_name='VActivity'`
* `default_package_format` via `-d vab:default_package_format='apk'`
* `default_min_sdk_version` = `-d vab:default_min_sdk_version=21`
* `default_base_files_path` via `-d vab:default_base_files_path=''`

# Using `vab` from the command line

For now please use the [Usage](https://github.com/vlang/vab#usage) section of the README.md
Expand Down
2 changes: 1 addition & 1 deletion vab.v
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ fn main() {

// Validate environment after options and input has been resolved
opt.validate_env()

// Ensure the "VIP" fields are sat before launch
opt.ensure_launch_fields()

// Keystore file
Expand Down

0 comments on commit 5725aea

Please sign in to comment.