Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ android/app/google-services.json
tools/
.omc/
functions/lib/

# goldie: generated store assets (captures + config are tracked)
goldie/out/
goldie/goldie.design.json
17 changes: 16 additions & 1 deletion THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Relevant paths in this repository:
- `android/app/src/main/java/com/u1/slicer/` — JNI bridge, G-code parser, 3D viewers
- `android/app/src/main/java/org/crabcore/u1control/slicing/` — Helix integration layer
- `android/app/src/main/jniLibs/arm64-v8a/libprusaslicer-jni.so` — prebuilt slicing engine
- `android/app/src/main/assets/` — Orca U1 machine/process profiles and GL shaders
- `android/app/src/main/assets/` — Orca machine/process profiles, vendor build-plate
models under `bed/`, and GL shaders

## Slicing engine lineage

Expand All @@ -37,6 +38,20 @@ MakerWorld is a third-party service operated by Bambu Lab. Helix opens MakerWorl
pages in a WebView for user-initiated downloads; Helix does not redistribute
MakerWorld content.

## Bespok3d bootstrap packages

The Android app contains the unmodified bootstrap packages distributed with the
official Bespok3d Desktop v0.7.3 release:

- `bespok3d-daemon` 0.12.24 — https://github.com/Bespok3d/daemon
- `bespok3d-jinni-snapmaker-u1` 0.1.10 — https://github.com/Bespok3d/adapters

Both projects are licensed AGPL-3.0-or-later. Their signed manifests,
documentation, dependency metadata, and upstream copyright notices remain
inside `android/app/src/main/assets/bespok3d/bootstrap-v0.7.3.zip`. Helix checks
the packages against Bespok3d's pinned OpenPGP publisher key and verifies every
manifest SHA-256 before an enrollment operation can read the payload.

## Your obligations when distributing Helix

If you distribute a build that includes the native slicer (release APK, CI
Expand Down
70 changes: 68 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ android {
applicationId 'org.crabcore.u1control'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 19
versionName "3.0.0"
versionCode 20
versionName "3.0.1"

buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
}
Expand Down Expand Up @@ -139,11 +139,31 @@ android {
}
}
packagingOptions {
resources {
// HiveMQ pulls in half a dozen Netty modules and each ships its own
// copy of these, which AGP will not merge. They are a jar index and
// a build stamp — nothing needs them at runtime.
excludes += [
'META-INF/INDEX.LIST',
'META-INF/io.netty.versions.properties',
// Several Java-versioned dependencies carry the same OSGi
// descriptor. Android does not use OSGi metadata at runtime.
'META-INF/versions/**/OSGI-INF/MANIFEST.MF',
]
}
jniLibs {
def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false'
useLegacyPackaging enableLegacyPackaging.toBoolean()
}
}
testOptions {
unitTests {
// The Bambu transport logs through android.util.Log, whose methods
// throw "not mocked" in a plain JVM test. The live tests exercise
// real sockets, not the framework, so returning defaults is enough.
returnDefaultValues = true
}
}
androidResources {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
}
Expand All @@ -169,17 +189,63 @@ android {
}
}

// The live Bambu tests talk to a real printer, so they read its address and
// credentials from the environment rather than from anything committed here.
// Without these the tests skip, which keeps CI and clean checkouts green.
tasks.withType(Test).configureEach {
systemProperty "helix.appProjectDir", project.projectDir.absolutePath
[
"BAMBU_HOST",
"BAMBU_SERIAL",
"BAMBU_ACCESS_CODE",
"BAMBU_DUMP_DIR",
"BESPOK3D_U1_HOST",
"BESPOK3D_U1_PASSWORD",
].each { key ->
def value = System.getenv(key)
if (value) {
environment key, value
}
}
testLogging {
showStandardStreams = true
events "passed", "skipped", "failed"
}
}

dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
testImplementation("junit:junit:4.13.2")
// The Android stub jar plus returnDefaultValues makes every JSONObject read
// return a default, so JSON parsers silently "pass" against nothing. A real
// implementation on the test classpath makes them testable.
testImplementation("org.json:json:20231013")

implementation platform('com.google.firebase:firebase-bom:34.16.0')
implementation 'com.google.firebase:firebase-messaging'

// Encrypted MakerWorld session-cookie storage (Android Keystore-backed).
implementation("androidx.security:security-crypto:1.1.0-alpha06")

// Bambu Lab printers speak MQTT over TLS on 8883 with a self-signed cert.
// HiveMQ is the only maintained Java client that lets us swap in a
// permissive TrustManagerFactory — see bambu/BambuMqttModule.kt.
implementation("com.hivemq:hivemq-mqtt-client:1.3.17")

// Bambu P1/X1 printers use implicit FTPS and require the data connection
// to resume the control connection's TLS session. Commons Net supplies the
// FTP state machine; BCJSSE is used because its public API can explicitly
// select the session to resume (Android's JSSE API cannot).
implementation("commons-net:commons-net:3.13.0")
implementation("org.bouncycastle:bcprov-jdk18on:1.83")
implementation("org.bouncycastle:bctls-jdk18on:1.83")
implementation("org.bouncycastle:bcpg-jdk18on:1.83")

// Bespok3d enrollment begins with a read-only SSH preflight against the U1.
// This maintained JSch fork supports the stock firmware's Ed25519 host key.
implementation("com.github.mwiede:jsch:2.28.6")

def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
Expand Down
9 changes: 9 additions & 0 deletions android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,13 @@
-keep class com.swmansion.reanimated.** { *; }
-keep class com.facebook.react.turbomodule.** { *; }

# HiveMQ MQTT client (Bambu Lab LAN transport). It sits on Netty, which
# references optional native transports and JDK-only classes that do not exist
# on Android — R8 must not treat those as missing-class errors.
-dontwarn io.netty.**
-dontwarn com.hivemq.client.**
-dontwarn org.slf4j.**
-dontwarn java.lang.management.**
-keep class io.netty.channel.socket.nio.** { *; }

# Add any project specific keep options here:
Binary file added android/app/src/main/assets/bed/ad5x_bed.stl
Binary file not shown.
Binary file not shown.
Binary file added android/app/src/main/assets/bed/bambu_x1_bed.stl
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading