building mobile nebula
This commit is contained in:
parent
f5af5eaba7
commit
a083661e00
388
src/_posts/2021-01-30-building-mobile-nebula.md
Normal file
388
src/_posts/2021-01-30-building-mobile-nebula.md
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
---
|
||||||
|
title: >-
|
||||||
|
Building Mobile Nebula
|
||||||
|
description: >-
|
||||||
|
Getting my hands dirty with Android development.
|
||||||
|
---
|
||||||
|
|
||||||
|
This post is going to be cheating a bit. I want to start working on adding DNS
|
||||||
|
resolver configuration to the [mobile nebula][mobile_nebula] app (if you don't
|
||||||
|
know nebula, [check it out][nebula], it's well worth knowing about), but I also
|
||||||
|
need to write a blog post for this week, so I'm combining the two exercises.
|
||||||
|
This post will essentially be my notes from my progress on today's task.
|
||||||
|
|
||||||
|
(Protip: listen to [this][heilung] while following along to achieve the proper
|
||||||
|
open-source programming aesthetic.)
|
||||||
|
|
||||||
|
The current mobile nebula app works very well, but it is lacking one major
|
||||||
|
feature: the ability to specify custom DNS resolvers. This is important because
|
||||||
|
I want to be able to access resources on my nebula network by their hostname,
|
||||||
|
not their IP. Android does everything in its power to make DNS configuration
|
||||||
|
impossible, and essentially the only way to actually accomplish this is by
|
||||||
|
specifying the DNS resolvers within the app. I go into more details about why
|
||||||
|
Android is broken [here][dns_issue].
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Before I can make changes to the app I need to make sure I can correctly build
|
||||||
|
it in the first place, so that's the major task for today. The first step to
|
||||||
|
doing so is to install the project's dependencies. As described in the
|
||||||
|
[mobile_nebula][mobile_nebula] README, the dependencies are:
|
||||||
|
|
||||||
|
- [`flutter`](https://flutter.dev/docs/get-started/install)
|
||||||
|
- [`gomobile`](https://godoc.org/golang.org/x/mobile/cmd/gomobile)
|
||||||
|
- [`android-studio`](https://developer.android.com/studio)
|
||||||
|
- [Enable NDK](https://developer.android.com/studio/projects/install-ndk)
|
||||||
|
|
||||||
|
It should be noted that as of writing I haven't used any of these tools ever,
|
||||||
|
and have only done a small amount of android programming, probably 7 or 8 years
|
||||||
|
ago, so I'm going to have to walk the line between figuring out problems on the
|
||||||
|
fly and not having to completely learning these entire ecosystems; there's only
|
||||||
|
so many hours in a weekend, after all.
|
||||||
|
|
||||||
|
I'm running [Archlinux][arch] so I install android-studio and flutter by
|
||||||
|
doing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yay -Sy android-studio flutter
|
||||||
|
```
|
||||||
|
|
||||||
|
And I install `gomobile`, according to its [documentation][gomobile] via:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get golang.org/x/mobile/cmd/gomobile
|
||||||
|
gomobile init
|
||||||
|
```
|
||||||
|
|
||||||
|
Now I startup android-studio and go through the setup wizard for it. I choose
|
||||||
|
standard setup because customized setup doesn't actually offer any interesting
|
||||||
|
options. Next android-studio spends approximately two lifetimes downloading
|
||||||
|
dependencies while my eyesight goes blurry because I'm drinking my coffee too
|
||||||
|
fast.
|
||||||
|
|
||||||
|
It's annoying that I need to install these dependencies, especially
|
||||||
|
android-studio, in order to build this project. A future goal of mine is to nix
|
||||||
|
this whole thing up, and make a build pipeline where you can provide a full
|
||||||
|
nebula configuration file and it outputs a custom APK file for that specific
|
||||||
|
config; zero configuration required at runtime. This will be useful for
|
||||||
|
lazy/non-technical users who want to be part of the nebula network.
|
||||||
|
|
||||||
|
Once android-studio starts up I'm not quite done yet: there's still the NDK
|
||||||
|
which must be enabled. The instructions given by the link in
|
||||||
|
[mobile_nebula][mobile_nebula]'s README explain doing this pretty well, but it's
|
||||||
|
important to install the specific version indicated in the mobile_nebula repo
|
||||||
|
(`21.0.6113669` at time of writing). Only another 1GB of dependency downloading
|
||||||
|
to go....
|
||||||
|
|
||||||
|
While waiting for the NDK to download I run `flutter doctor` to make sure
|
||||||
|
flutter is working, and it gives me some permissions errors. [This blog
|
||||||
|
post][flutter_blog] gives some tips on setting up, and after running the
|
||||||
|
following...
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo groupadd flutterusers
|
||||||
|
sudo gpasswd -a $USER flutterusers
|
||||||
|
sudo chown -R :flutterusers /opt/flutter
|
||||||
|
sudo chmod -R g+w /opt/flutter/
|
||||||
|
newgrp flutterusers
|
||||||
|
```
|
||||||
|
|
||||||
|
... I'm able to run `flutter doctor`. It gives the following output:
|
||||||
|
|
||||||
|
```
|
||||||
|
[✓] Flutter (Channel stable, 1.22.6, on Linux, locale en_US.UTF-8)
|
||||||
|
|
||||||
|
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
|
||||||
|
✗ Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses
|
||||||
|
[!] Android Studio
|
||||||
|
✗ Flutter plugin not installed; this adds Flutter specific functionality.
|
||||||
|
✗ Dart plugin not installed; this adds Dart specific functionality.
|
||||||
|
[!] Connected device
|
||||||
|
! No devices available
|
||||||
|
|
||||||
|
! Doctor found issues in 3 categories.
|
||||||
|
```
|
||||||
|
|
||||||
|
The first issue is easily solved as per the instructions given. The second is
|
||||||
|
solved by finding the plugin manager in android-studio and installing the
|
||||||
|
flutter plugin (which installs the dart plugin as a dependency, we call that a
|
||||||
|
twofer).
|
||||||
|
|
||||||
|
After installing the plugin the doctor command still complains about not finding
|
||||||
|
the plugins, but the above mentioned blog post indicates to me that this is
|
||||||
|
expected. It's comforting to know that the problems indicated by the doctor may
|
||||||
|
or may not be real problems.
|
||||||
|
|
||||||
|
The [blog post][flutter_blog] also indicates that I need `openjdk-8` installed,
|
||||||
|
so I do:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yay -S jdk8-openjdk
|
||||||
|
```
|
||||||
|
|
||||||
|
And use the `archlinux-java` command to confirm that that is indeed the default
|
||||||
|
version for my shell. The [mobile_nebula][mobile_nebula] helpfully expects an
|
||||||
|
`env.sh` file to exist in the root, so if openjdk-8 wasn't already the default I
|
||||||
|
could make it so within that file.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
At this point I think I'm ready to try actually building an APK. Thoughts and
|
||||||
|
prayers required. I run the following in a terminal, since for some reason the
|
||||||
|
`Build > Flutter > Build APK` dropdown button in android-studio did nothing.
|
||||||
|
|
||||||
|
```
|
||||||
|
flutter build apk
|
||||||
|
```
|
||||||
|
|
||||||
|
It takes quite a while to run, but in the end it errors with:
|
||||||
|
|
||||||
|
```
|
||||||
|
make: 'mobileNebula.aar' is up to date.
|
||||||
|
cp: cannot create regular file '../android/app/src/main/libs/mobileNebula.aar': No such file or directory
|
||||||
|
|
||||||
|
FAILURE: Build failed with an exception.
|
||||||
|
|
||||||
|
* Where:
|
||||||
|
Build file '/tmp/src/mobile_nebula/android/app/build.gradle' line: 95
|
||||||
|
|
||||||
|
* What went wrong:
|
||||||
|
A problem occurred evaluating project ':app'.
|
||||||
|
> Process 'command './gen-artifacts.sh'' finished with non-zero exit value 1
|
||||||
|
|
||||||
|
* Try:
|
||||||
|
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
|
||||||
|
|
||||||
|
* Get more help at https://help.gradle.org
|
||||||
|
|
||||||
|
BUILD FAILED in 1s
|
||||||
|
Running Gradle task 'bundleRelease'...
|
||||||
|
Running Gradle task 'bundleRelease'... Done 1.7s
|
||||||
|
Gradle task bundleRelease failed with exit code 1
|
||||||
|
```
|
||||||
|
|
||||||
|
I narrow down the problem to the `./gen-artifacts.sh` script in the repo's root,
|
||||||
|
which takes in either `android` or `ios` as an argument. Running it directly
|
||||||
|
as `./gen-artifacts.sh android` results in the same error:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make: 'mobileNebula.aar' is up to date.
|
||||||
|
cp: cannot create regular file '../android/app/src/main/libs/mobileNebula.aar': No such file or directory
|
||||||
|
```
|
||||||
|
|
||||||
|
So now I gotta figure out wtf that `mobileNebula.aar` file is. The first thing I
|
||||||
|
note is that not only is that file not there, but the `libs` directory it's
|
||||||
|
supposed to be present in is also not there. So I suspect that there's a missing
|
||||||
|
build step somewhere.
|
||||||
|
|
||||||
|
I search for the string `mobileNebula.aar` within the project using
|
||||||
|
[ag][silver_searcher] and find that it's built by `nebula/Makefile` as follows:
|
||||||
|
|
||||||
|
```make
|
||||||
|
mobileNebula.aar: *.go
|
||||||
|
gomobile bind -trimpath -v --target=android
|
||||||
|
```
|
||||||
|
|
||||||
|
So that file is made by `gomobile`, good to know! Additionally the file is
|
||||||
|
actually there in the `nebula` directory, so I suspect there's just a missing
|
||||||
|
build step to move it into `android/app/src/main/libs`. Via some more `ag`-ing I
|
||||||
|
find that the code which is supposed to move the `mobileNebula.aar` file is in
|
||||||
|
the `gen-artifacts.sh` script, but that script doesn't create the `libs` folder
|
||||||
|
as it ought to. I apply the following diff:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
diff --git a/gen-artifacts.sh b/gen-artifacts.sh
|
||||||
|
index 601ed7b..4f73b4c 100755
|
||||||
|
--- a/gen-artifacts.sh
|
||||||
|
+++ b/gen-artifacts.sh
|
||||||
|
@@ -16,7 +16,7 @@ if [ "$1" = "ios" ]; then
|
||||||
|
elif [ "$1" = "android" ]; then
|
||||||
|
# Build nebula for android
|
||||||
|
make mobileNebula.aar
|
||||||
|
- rm -rf ../android/app/src/main/libs/mobileNebula.aar
|
||||||
|
+ mkdir -p ../android/app/src/main/libs
|
||||||
|
cp mobileNebula.aar ../android/app/src/main/libs/mobileNebula.aar
|
||||||
|
|
||||||
|
else
|
||||||
|
```
|
||||||
|
|
||||||
|
(The `rm -rf` isn't necessary, since a) that file is about to be overwritten by
|
||||||
|
the subsequent `cp` whether or not it's there, and b) it's just deleting a
|
||||||
|
single file so the `-rf` is an unnecessary risk).
|
||||||
|
|
||||||
|
At this point I re-run `flutter build apk` and receive a new error. Progress!
|
||||||
|
|
||||||
|
```
|
||||||
|
A problem occurred evaluating root project 'android'.
|
||||||
|
> A problem occurred configuring project ':app'.
|
||||||
|
> Removing unused resources requires unused code shrinking to be turned on. See http://d.android.com/r/tools/shrink-resources.html for more information.
|
||||||
|
```
|
||||||
|
|
||||||
|
I recall that in the original [mobile_nebula][mobile_nebula] README it mentions
|
||||||
|
to run the `flutter build` command with the `--no-shrink` option, so I try:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flutter build apk --no-shrink
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally we really get somewhere. The command takes a very long time to run as it
|
||||||
|
downloads yet more dependencies (mostly android SDK stuff from the looks of it),
|
||||||
|
but unfortunately still errors out:
|
||||||
|
|
||||||
|
```
|
||||||
|
Execution failed for task ':app:processReleaseResources'.
|
||||||
|
> Could not resolve all files for configuration ':app:releaseRuntimeClasspath'.
|
||||||
|
> Failed to transform mobileNebula-.aar (:mobileNebula:) to match attributes {artifactType=android-compiled-dependencies-resources, org.gradle.status=integration}.
|
||||||
|
> Execution failed for AarResourcesCompilerTransform: /home/mediocregopher/.gradle/caches/transforms-2/files-2.1/735fc805916d942f5311063c106e7363/jetified-mobileNebula.
|
||||||
|
> /home/mediocregopher/.gradle/caches/transforms-2/files-2.1/735fc805916d942f5311063c106e7363/jetified-mobileNebula/AndroidManifest.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
Time for more `ag`-ing. I find the file `android/app/build.gradle`, which has
|
||||||
|
the following block:
|
||||||
|
|
||||||
|
```
|
||||||
|
implementation (name:'mobileNebula', ext:'aar') {
|
||||||
|
exec {
|
||||||
|
workingDir '../../'
|
||||||
|
environment("ANDROID_NDK_HOME", android.ndkDirectory)
|
||||||
|
environment("ANDROID_HOME", android.sdkDirectory)
|
||||||
|
commandLine './gen-artifacts.sh', 'android'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
I never set up the `ANDROID_HOME` or `ANDROID_NDK_HOME` environment variables,
|
||||||
|
and I suppose that if I'm running the flutter command outside of android-studio
|
||||||
|
there wouldn't be a way for flutter to know those values, so I try setting them
|
||||||
|
within my `env.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ANDROID_HOME=~/Android/Sdk
|
||||||
|
export ANDROID_NDK_HOME=~/Android/Sdk/ndk/21.0.6113669
|
||||||
|
```
|
||||||
|
|
||||||
|
Re-running the build command still results in the same error. But it occurs to
|
||||||
|
me that I probably had built the `mobileNebula.aar` without those set
|
||||||
|
previously, so maybe it was built with the wrong NDK version or something. I
|
||||||
|
tried deleting `nebula/mobileNebula.aar` and try building again. This time...
|
||||||
|
new errors! Lots of them! Big ones and small ones!
|
||||||
|
|
||||||
|
At this point I'm a bit fed up, and want to try a completely fresh build. I back
|
||||||
|
up my modified `env.sh` and `gen-artifacts.sh` files, delete the `mobile_nebula`
|
||||||
|
repo, re-clone it, reinstall those files, and try building again. This time just
|
||||||
|
a single error:
|
||||||
|
|
||||||
|
```
|
||||||
|
Execution failed for task ':app:lintVitalRelease'.
|
||||||
|
> Could not resolve all artifacts for configuration ':app:debugRuntimeClasspath'.
|
||||||
|
> Failed to transform libs.jar to match attributes {artifactType=processed-jar, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}.
|
||||||
|
> Execution failed for JetifyTransform: /tmp/src/mobile_nebula/build/app/intermediates/flutter/debug/libs.jar.
|
||||||
|
> Failed to transform '/tmp/src/mobile_nebula/build/app/intermediates/flutter/debug/libs.jar' using Jetifier. Reason: FileNotFoundException, message: /tmp/src/mobile_nebula/build/app/intermediates/flutter/debug/libs.jar (No such file or directory). (Run with --stacktrace for more details.)
|
||||||
|
Please file a bug at http://issuetracker.google.com/issues/new?component=460323.
|
||||||
|
```
|
||||||
|
|
||||||
|
So that's cool, apparently there's a bug with flutter and I should file a
|
||||||
|
support ticket? Well, probably not. It seems that while
|
||||||
|
`build/app/intermediates/flutter/debug/libs.jar` indeed doesn't exist in the
|
||||||
|
repo, `build/app/intermediates/flutter/release/libs.jar` _does_, so this appears
|
||||||
|
to possibly be an issue in declaring which build environment is being used.
|
||||||
|
|
||||||
|
After some googling I found [this flutter issue][flutter_issue] related to the
|
||||||
|
error. Tldr: gradle's not playing nicely with flutter. Downgrading could help,
|
||||||
|
but apparently building with the `--debug` flag also works. I don't want to
|
||||||
|
build a release version anyway, so this sits fine with me. I run...
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flutter build apk --no-shrink --debug
|
||||||
|
```
|
||||||
|
|
||||||
|
And would you look at that, I got a result!
|
||||||
|
|
||||||
|
```
|
||||||
|
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Building was probably the hard part, but I'm not totally out of the woods yet.
|
||||||
|
Theoretically I could email this apk to my phone or something, but I'd like
|
||||||
|
something with a faster turnover time; I need `adb`.
|
||||||
|
|
||||||
|
I install `adb` via the `android-tools` package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yay -S android-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
Before `adb` will work, however, I need to turn on USB debugging on my phone,
|
||||||
|
which I do by following [this article][usb_debugging]. Once connected I confirm
|
||||||
|
that `adb` can talk to my phone by doing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb devices
|
||||||
|
```
|
||||||
|
|
||||||
|
And then, finally, I can install the apk:
|
||||||
|
|
||||||
|
```
|
||||||
|
adb install build/app/outputs/flutter-apk/app-debug.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
NOT SO FAST! MORE ERRORS!
|
||||||
|
|
||||||
|
```
|
||||||
|
adb: failed to install build/app/outputs/flutter-apk/app-debug.apk: Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package net.defined.mobile_nebula signatures do not match previously installed version; ignoring!]
|
||||||
|
```
|
||||||
|
|
||||||
|
I'm guessing this is because I already have the real nebula app installed. I
|
||||||
|
uninstall it and try again.
|
||||||
|
|
||||||
|
AND IT WORKS!!! FUCK YEAH!
|
||||||
|
|
||||||
|
```
|
||||||
|
Performing Streamed Install
|
||||||
|
Success
|
||||||
|
```
|
||||||
|
|
||||||
|
I can open the nebula app on my phone and it works... fine. There's some
|
||||||
|
pre-existing networks already installed, which isn't the case for the Play Store
|
||||||
|
version as far as I can remember, so I suspect those are only there in the
|
||||||
|
debugging build. Unfortunately the presence of these test networks causes the
|
||||||
|
app the throw a bunch of errors because it can't contact those networks. Oh well.
|
||||||
|
|
||||||
|
The presence of those test networks, in a way, is actually a good thing, as it
|
||||||
|
means there's probably already a starting point for what I want to do: building
|
||||||
|
a per-device nebula app with a config preloaded into it.
|
||||||
|
|
||||||
|
## Further Steps
|
||||||
|
|
||||||
|
Beyond continuing on towards my actual goal of adding DNS resolvers to this app,
|
||||||
|
there's a couple of other paths I could potentially go down at this point.
|
||||||
|
|
||||||
|
* As mentioned, nixify the whole thing. I'm 99% sure the android-studio GUI
|
||||||
|
isn't actually needed at all, and I only used it for installing the CMake and
|
||||||
|
NDK plugins because I didn't bother to look up how to do it on the CLI.
|
||||||
|
|
||||||
|
* Figuring out how to do a proper release build would be great, just for my own
|
||||||
|
education. Based on the [flutter issue][flutter_issue] it's possible that all
|
||||||
|
that's needed is to downgrade gradle, but maybe that's not so easy.
|
||||||
|
|
||||||
|
* Get an android emulator working so that I don't have to install to my phone
|
||||||
|
everytime I want to test the app out. I'm not sure if that will also work for
|
||||||
|
the VPN aspect of the app, but it will at least help me iterate on UI changes
|
||||||
|
faster.
|
||||||
|
|
||||||
|
But at this point I'm done for the day, I'll continue on this project some other
|
||||||
|
time.
|
||||||
|
|
||||||
|
[mobile_nebula]: https://github.com/DefinedNet/mobile_nebula
|
||||||
|
[nebula]: https://slack.engineering/introducing-nebula-the-open-source-global-overlay-network-from-slack/
|
||||||
|
[dns_issue]: https://github.com/DefinedNet/mobile_nebula/issues/9
|
||||||
|
[arch]: https://archlinux.org/
|
||||||
|
[android_wiki]: https://wiki.archlinux.org/index.php/Android#Making_/opt/android-sdk_group-writeable
|
||||||
|
[heilung]: https://youtu.be/SMJ7pxqk5d4?t=220
|
||||||
|
[flutter_blog]: https://www.rockyourcode.com/how-to-get-flutter-and-android-working-on-arch-linux/
|
||||||
|
[gomobile]: https://pkg.go.dev/golang.org/x/mobile/cmd/gomobile
|
||||||
|
[silver_searcher]: https://github.com/ggreer/the_silver_searcher
|
||||||
|
[flutter_issue]: https://github.com/flutter/flutter/issues/58247
|
||||||
|
[usb_debugging]: https://www.droidviews.com/how-to-enable-developer-optionsusb-debugging-mode-on-devices-with-android-4-2-jelly-bean/
|
Loading…
Reference in New Issue
Block a user