mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-20 06:28:27 +02:00
feat(build): require Discord in production and keep Lite opt-in
This commit is contained in:
1 parent
541bfc4002
commit
9c0b22e2c8
9 files changed
+333
-17
No files matched your search
@@ -50,6 +50,8 @@ jobs:
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
needs: get-version
|
||||
env:
|
||||
SPOTIFLAC_DISCORD_SDK: "1"
|
||||
|
||||
steps:
|
||||
- name: Free disk space
|
||||
@@ -142,7 +144,7 @@ jobs:
|
||||
|
||||
- name: Build release APKs
|
||||
run: |
|
||||
bash scripts/build_android.sh --target lib/main.dart
|
||||
bash scripts/build_android.sh --production --target lib/main.dart
|
||||
ls -la build/app/outputs/flutter-apk/
|
||||
|
||||
- name: Sign and verify release APKs (V1/V2/V3/V4)
|
||||
@@ -212,9 +214,9 @@ jobs:
|
||||
run: |
|
||||
apk_dir=build/app/outputs/flutter-apk
|
||||
python3 scripts/check_backend_apk.py "$apk_dir/SpotiFLAC-${VERSION}-arm64.apk" \
|
||||
--backend rust --abis arm64-v8a
|
||||
--backend rust --abis arm64-v8a --discord-sdk
|
||||
python3 scripts/check_backend_apk.py "$apk_dir/SpotiFLAC-${VERSION}-arm32.apk" \
|
||||
--backend rust --abis armeabi-v7a
|
||||
--backend rust --abis armeabi-v7a --discord-sdk
|
||||
for abi in arm64 arm32; do
|
||||
"$ANDROID_HOME/build-tools/37.0.0/zipalign" -c -P 16 4 \
|
||||
"$apk_dir/SpotiFLAC-${VERSION}-${abi}.apk"
|
||||
@@ -231,6 +233,8 @@ jobs:
|
||||
build-ios:
|
||||
runs-on: macos-15
|
||||
needs: get-version # Only depends on version, NOT android build!
|
||||
env:
|
||||
SPOTIFLAC_DISCORD_SDK: "1"
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -283,7 +287,13 @@ jobs:
|
||||
|
||||
- name: Configure Rust application pods
|
||||
working-directory: ios
|
||||
run: pod install
|
||||
run: |
|
||||
test -f ../third_party/spotiflac_discord/ios/Frameworks/discord_partner_sdk.xcframework/Info.plist || {
|
||||
echo "Production requires the official Discord SDK. Run scripts/setup_discord_sdk.sh in the build environment first." >&2
|
||||
exit 1
|
||||
}
|
||||
test -f ../third_party/spotiflac_discord/ios/Frameworks/Discord-License-Notices.txt
|
||||
pod install
|
||||
|
||||
- name: Build iOS (unsigned)
|
||||
run: |
|
||||
@@ -307,6 +317,8 @@ jobs:
|
||||
|
||||
- name: Audit Rust iOS archive before packaging
|
||||
run: |
|
||||
test -f ios/build/Runner.xcarchive/Products/Applications/Runner.app/Frameworks/discord_partner_sdk.framework/discord_partner_sdk
|
||||
test -f ios/build/Runner.xcarchive/Products/Applications/Runner.app/Discord-License-Notices.txt
|
||||
python3 -m unittest discover -s scripts -p 'test_check_backend_ios.py'
|
||||
python3 scripts/check_backend_ios.py \
|
||||
ios/build/Runner.xcarchive/Products/Applications/Runner.app \
|
||||
|
||||
@@ -67,6 +67,21 @@ Gradle builds the Rust native artifacts automatically. Tool versions are pinned
|
||||
Start with the [Contributing Guide](CONTRIBUTING.md) for the development setup,
|
||||
project boundaries, validation commands, and pull request checklist.
|
||||
|
||||
Build production APKs with `bash scripts/build_android.sh --production`;
|
||||
this requires the staged Discord SDK and rejects Lite. CI releases use this
|
||||
mode and require Discord on both Android and iOS. Stage the official SDK with
|
||||
`scripts/setup_discord_sdk.sh` in the build environment before releasing;
|
||||
the SDK is not committed to the repository. A fresh hosted runner must be
|
||||
provided with the SDK before these release checks can pass.
|
||||
|
||||
For development release APKs, use `bash scripts/build_android.sh`; use `--lite` to omit
|
||||
the optional Discord SDK while keeping playback and downloads. Full builds
|
||||
remain the default. To build only ARM64, set
|
||||
`SPOTIFLAC_RUST_ANDROID_ABIS=arm64-v8a`. The script uses the Flutter version in
|
||||
`.fvmrc` and audits the selected split APKs and universal APK. For iOS Lite,
|
||||
run CocoaPods and the app build with `SPOTIFLAC_DISCORD_SDK=0`; an existing Pods
|
||||
installation must be regenerated with that setting.
|
||||
|
||||
For native iOS codec checks, see the [FFmpeg capability probe](scripts/README_ios_ffmpeg_capabilities.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -20,6 +20,7 @@ val rustAndroidAbis = providers.environmentVariable("SPOTIFLAC_RUST_ANDROID_ABIS
|
||||
.get()
|
||||
.split(",")
|
||||
val supportedRustAndroidAbis = setOf("arm64-v8a", "armeabi-v7a")
|
||||
val discordSdkEnabled = providers.environmentVariable("SPOTIFLAC_DISCORD_SDK").orElse("1").get() != "0"
|
||||
require(rustAndroidAbis.size == rustAndroidAbis.toSet().size) {
|
||||
"SPOTIFLAC_RUST_ANDROID_ABIS must not contain duplicate ABIs"
|
||||
}
|
||||
@@ -36,7 +37,7 @@ android {
|
||||
buildConfig = true
|
||||
}
|
||||
packaging {
|
||||
jniLibs.pickFirsts += "**/libdiscord_partner_sdk.so"
|
||||
if (discordSdkEnabled) jniLibs.pickFirsts += "**/libdiscord_partner_sdk.so"
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -171,7 +172,7 @@ flutter {
|
||||
|
||||
dependencies {
|
||||
val discordSdk = file("../../third_party/spotiflac_discord/sdk/discord_partner_sdk.aar")
|
||||
if (discordSdk.exists()) {
|
||||
if (discordSdkEnabled && discordSdk.exists()) {
|
||||
implementation(files(discordSdk))
|
||||
}
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
|
||||
|
||||
@@ -6,33 +6,112 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
OUTPUT_DIR="$PROJECT_DIR/build/app/outputs/flutter-apk"
|
||||
FLUTTER_ARGS=()
|
||||
PRODUCTION_BUILD=0
|
||||
LITE_BUILD=0
|
||||
for argument in "$@"; do
|
||||
case "$argument" in
|
||||
--production) PRODUCTION_BUILD=1 ;;
|
||||
--lite) LITE_BUILD=1; export SPOTIFLAC_DISCORD_SDK=0 ;;
|
||||
--target-platform|--target-platform=*|--split-per-abi|--no-split-per-abi)
|
||||
echo "Error: set SPOTIFLAC_RUST_ANDROID_ABIS to select the release APK architectures." >&2
|
||||
exit 1
|
||||
;;
|
||||
*) FLUTTER_ARGS+=("$argument") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$PRODUCTION_BUILD" == "1" ]]; then
|
||||
if [[ "$LITE_BUILD" == "1" ]]; then
|
||||
echo "Error: production builds require Discord; --production cannot be combined with --lite." >&2
|
||||
exit 1
|
||||
fi
|
||||
export SPOTIFLAC_DISCORD_SDK=1
|
||||
fi
|
||||
|
||||
case "${SPOTIFLAC_DISCORD_SDK:-1}" in
|
||||
0|1) ;;
|
||||
*) echo "Error: SPOTIFLAC_DISCORD_SDK must be 0 (Lite) or 1 (full)." >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
ANDROID_ABIS_RAW="${SPOTIFLAC_RUST_ANDROID_ABIS-arm64-v8a,armeabi-v7a}"
|
||||
case "$ANDROID_ABIS_RAW" in
|
||||
arm64-v8a|armeabi-v7a|arm64-v8a,armeabi-v7a|armeabi-v7a,arm64-v8a) ;;
|
||||
*)
|
||||
echo "Error: SPOTIFLAC_RUST_ANDROID_ABIS must contain arm64-v8a and/or armeabi-v7a, comma-separated without spaces or duplicates." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
export SPOTIFLAC_RUST_ANDROID_ABIS="$ANDROID_ABIS_RAW"
|
||||
IFS=',' read -r -a ANDROID_ABIS <<< "$ANDROID_ABIS_RAW"
|
||||
TARGET_PLATFORMS=()
|
||||
for abi in "${ANDROID_ABIS[@]}"; do
|
||||
case "$abi" in
|
||||
arm64-v8a) TARGET_PLATFORMS+=(android-arm64) ;;
|
||||
armeabi-v7a) TARGET_PLATFORMS+=(android-arm) ;;
|
||||
esac
|
||||
done
|
||||
TARGET_PLATFORM_LIST="$(IFS=','; echo "${TARGET_PLATFORMS[*]}")"
|
||||
|
||||
if [[ "$PRODUCTION_BUILD" == "1" ]]; then
|
||||
SDK_ROOT="$PROJECT_DIR/third_party/spotiflac_discord/sdk"
|
||||
for sdk_file in discord_partner_sdk.aar notices/Discord-License-Notices.txt android/prefab/modules/discord_partner_sdk/include/discordpp.h; do
|
||||
if [[ ! -f "$SDK_ROOT/$sdk_file" ]]; then
|
||||
echo "Error: production requires the staged Discord SDK ($sdk_file). Run scripts/setup_discord_sdk.sh with the official SDK first." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
for abi in "${ANDROID_ABIS[@]}"; do
|
||||
if [[ ! -f "$SDK_ROOT/android/jni/$abi/libdiscord_partner_sdk.so" ]]; then
|
||||
echo "Error: production requires the Discord SDK library for $abi." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
AUDIT_FLAGS=()
|
||||
if [[ -f "$PROJECT_DIR/third_party/spotiflac_discord/sdk/discord_partner_sdk.aar" ]]; then
|
||||
if [[ "${SPOTIFLAC_DISCORD_SDK:-1}" != "0" && -f "$PROJECT_DIR/third_party/spotiflac_discord/sdk/discord_partner_sdk.aar" ]]; then
|
||||
AUDIT_FLAGS+=(--discord-sdk)
|
||||
fi
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
if [[ -x "$PROJECT_DIR/.fvm/flutter_sdk/bin/flutter" ]]; then
|
||||
FLUTTER_COMMAND=("$PROJECT_DIR/.fvm/flutter_sdk/bin/flutter")
|
||||
elif command -v fvm >/dev/null 2>&1; then
|
||||
FLUTTER_COMMAND=(fvm flutter)
|
||||
elif command -v flutter >/dev/null 2>&1; then
|
||||
FLUTTER_COMMAND=(flutter)
|
||||
else
|
||||
echo "Error: install the Flutter version pinned in .fvmrc with FVM." >&2
|
||||
exit 1
|
||||
fi
|
||||
PINNED_FLUTTER_VERSION="$(python3 -c 'import json, sys; print(json.load(open(sys.argv[1]))["flutter"])' "$PROJECT_DIR/.fvmrc")"
|
||||
FLUTTER_VERSION="$("${FLUTTER_COMMAND[@]}" --version --machine | python3 -c 'import json, sys; print(json.load(sys.stdin)["frameworkVersion"])')"
|
||||
if [[ "$FLUTTER_VERSION" != "$PINNED_FLUTTER_VERSION" ]]; then
|
||||
echo "Error: Flutter $PINNED_FLUTTER_VERSION is required; found $FLUTTER_VERSION." >&2
|
||||
exit 1
|
||||
fi
|
||||
BUILD_GIT_COMMIT="$(git rev-parse --short=8 HEAD)"
|
||||
flutter build apk \
|
||||
"${FLUTTER_COMMAND[@]}" build apk \
|
||||
--release \
|
||||
--split-per-abi \
|
||||
--target-platform android-arm,android-arm64 \
|
||||
--target-platform "$TARGET_PLATFORM_LIST" \
|
||||
--dart-define="GIT_COMMIT=$BUILD_GIT_COMMIT" \
|
||||
"$@"
|
||||
${FLUTTER_ARGS[@]+"${FLUTTER_ARGS[@]}"}
|
||||
|
||||
for target in armeabi-v7a arm64-v8a universal; do
|
||||
for target in "${ANDROID_ABIS[@]}" universal; do
|
||||
apk="app-$target-release.apk"
|
||||
abis="$target"
|
||||
if [[ "$target" == "universal" ]]; then
|
||||
apk=app-release.apk
|
||||
abis=armeabi-v7a,arm64-v8a
|
||||
abis="$ANDROID_ABIS_RAW"
|
||||
fi
|
||||
if [[ ! -f "$OUTPUT_DIR/$apk" ]]; then
|
||||
echo "Error: expected APK was not created: $OUTPUT_DIR/$apk" >&2
|
||||
exit 1
|
||||
fi
|
||||
python3 scripts/check_backend_apk.py "$OUTPUT_DIR/$apk" \
|
||||
--backend rust --abis "$abis" "${AUDIT_FLAGS[@]}"
|
||||
--backend rust --abis "$abis" ${AUDIT_FLAGS[@]+"${AUDIT_FLAGS[@]}"}
|
||||
done
|
||||
|
||||
echo "Built Android release APKs in $OUTPUT_DIR"
|
||||
@@ -0,0 +1,192 @@
|
||||
"""Check release selection and audits without building APKs or deleting artifacts."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
FLUTTER_STUB = """import json, os, sys
|
||||
from pathlib import Path
|
||||
args = sys.argv[1:]
|
||||
if Path(sys.argv[0]).name == 'fvm':
|
||||
assert args.pop(0) == 'flutter'
|
||||
with open(os.environ['BUILD_TEST_LOG'], 'a') as log:
|
||||
log.write(json.dumps({'tool': Path(sys.argv[0]).name, 'args': args,
|
||||
'sdk': os.environ.get('SPOTIFLAC_DISCORD_SDK', '1')}) + '\\n')
|
||||
if args == ['--version', '--machine']:
|
||||
print(json.dumps({'frameworkVersion': os.environ.get('BUILD_TEST_FLUTTER_VERSION', '3.47.5')}))
|
||||
else:
|
||||
assert args[:2] == ['build', 'apk']
|
||||
output = Path('build/app/outputs/flutter-apk')
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
for abi in os.environ['SPOTIFLAC_RUST_ANDROID_ABIS'].split(','):
|
||||
(output / ('app-' + abi + '-release.apk')).write_bytes(b'fixture split')
|
||||
(output / 'app-release.apk').write_bytes(b'fixture universal')
|
||||
"""
|
||||
|
||||
PYTHON_STUB = """import json, os, sys
|
||||
if sys.argv[1] == 'scripts/check_backend_apk.py':
|
||||
with open(os.environ['BUILD_TEST_LOG'], 'a') as log:
|
||||
log.write(json.dumps({'tool': 'audit', 'args': sys.argv[2:]}) + '\\n')
|
||||
else:
|
||||
os.execv(sys.executable, [sys.executable, *sys.argv[1:]])
|
||||
"""
|
||||
|
||||
|
||||
class AndroidBuildScriptTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
directory = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(directory.cleanup)
|
||||
self.project = Path(directory.name)
|
||||
(self.project / "scripts").mkdir()
|
||||
shutil.copyfile(Path(__file__).with_name("build_android.sh"), self.project / "scripts/build_android.sh")
|
||||
(self.project / ".fvmrc").write_text('{"flutter":"3.47.5"}')
|
||||
sdk = self.project / "third_party/spotiflac_discord/sdk"
|
||||
sdk.mkdir(parents=True)
|
||||
(sdk / "discord_partner_sdk.aar").write_bytes(b"staged fixture")
|
||||
for name in (
|
||||
"notices/Discord-License-Notices.txt",
|
||||
"android/prefab/modules/discord_partner_sdk/include/discordpp.h",
|
||||
"android/jni/arm64-v8a/libdiscord_partner_sdk.so",
|
||||
"android/jni/armeabi-v7a/libdiscord_partner_sdk.so",
|
||||
):
|
||||
path = sdk / name
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_bytes(b"staged fixture")
|
||||
self.tools = self.project / "tools"
|
||||
self.tools.mkdir()
|
||||
self.log = self.project / "calls.jsonl"
|
||||
self.env = os.environ.copy()
|
||||
for key in ("SPOTIFLAC_DISCORD_SDK", "SPOTIFLAC_RUST_ANDROID_ABIS"):
|
||||
self.env.pop(key, None)
|
||||
self.env.update(PATH=str(self.tools) + os.pathsep + os.defpath, BUILD_TEST_LOG=str(self.log))
|
||||
self.tool(self.tools / "python3", PYTHON_STUB)
|
||||
git = self.tools / "git"
|
||||
git.write_text("#!/bin/sh\necho 1234abcd\n")
|
||||
git.chmod(0o755)
|
||||
self.pinned = self.project / ".fvm/flutter_sdk/bin/flutter"
|
||||
self.tool(self.pinned, FLUTTER_STUB)
|
||||
|
||||
def tool(self, path, source):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text("#!" + sys.executable + "\n" + source)
|
||||
path.chmod(0o755)
|
||||
|
||||
def run_build(self, *args):
|
||||
return subprocess.run(
|
||||
["/bin/bash", str(self.project / "scripts/build_android.sh"), *args],
|
||||
cwd=self.project, env=self.env, text=True, capture_output=True,
|
||||
)
|
||||
|
||||
def calls(self):
|
||||
return [json.loads(line) for line in self.log.read_text().splitlines()]
|
||||
|
||||
def test_default_full_audits_two_splits_and_universal(self):
|
||||
result = self.run_build("--verbose")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
calls = self.calls()
|
||||
build = next(call for call in calls if call["args"][:2] == ["build", "apk"])
|
||||
self.assertIn("android-arm64,android-arm", build["args"])
|
||||
self.assertIn("--verbose", build["args"])
|
||||
audits = [call["args"] for call in calls if call["tool"] == "audit"]
|
||||
self.assertEqual([Path(args[0]).name for args in audits], [
|
||||
"app-arm64-v8a-release.apk", "app-armeabi-v7a-release.apk", "app-release.apk",
|
||||
])
|
||||
self.assertTrue(all("--discord-sdk" in args for args in audits))
|
||||
self.assertEqual(audits[-1][audits[-1].index("--abis") + 1], "arm64-v8a,armeabi-v7a")
|
||||
|
||||
def test_lite_single_abi_ignores_and_preserves_previous_artifacts(self):
|
||||
self.env["SPOTIFLAC_RUST_ANDROID_ABIS"] = "arm64-v8a"
|
||||
output = self.project / "build/app/outputs/flutter-apk"
|
||||
output.mkdir(parents=True)
|
||||
previous = output / "app-armeabi-v7a-release.apk"
|
||||
previous.write_bytes(b"previous build")
|
||||
result = self.run_build("--lite")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
calls = self.calls()
|
||||
build = next(call for call in calls if call["args"][:2] == ["build", "apk"])
|
||||
self.assertEqual(build["sdk"], "0")
|
||||
self.assertNotIn("--lite", build["args"])
|
||||
self.assertIn("android-arm64", build["args"])
|
||||
audits = [call["args"] for call in calls if call["tool"] == "audit"]
|
||||
self.assertEqual(len(audits), 2)
|
||||
self.assertTrue(all("--discord-sdk" not in args for args in audits))
|
||||
self.assertTrue(all(args[args.index("--abis") + 1] == "arm64-v8a" for args in audits))
|
||||
self.assertEqual(previous.read_bytes(), b"previous build")
|
||||
|
||||
def test_explicit_sdk_disable_is_honored_without_lite_argument(self):
|
||||
self.env["SPOTIFLAC_DISCORD_SDK"] = "0"
|
||||
self.env["SPOTIFLAC_RUST_ANDROID_ABIS"] = "armeabi-v7a"
|
||||
result = self.run_build()
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
audits = [call["args"] for call in self.calls() if call["tool"] == "audit"]
|
||||
self.assertEqual(len(audits), 2)
|
||||
self.assertTrue(all("--discord-sdk" not in args for args in audits))
|
||||
self.assertTrue(all(args[args.index("--abis") + 1] == "armeabi-v7a" for args in audits))
|
||||
|
||||
def test_fvm_fallback_uses_pinned_version(self):
|
||||
self.pinned.unlink()
|
||||
self.tool(self.tools / "fvm", FLUTTER_STUB)
|
||||
result = self.run_build()
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(self.calls()[0]["tool"], "fvm")
|
||||
|
||||
def test_production_requires_full_even_with_inherited_sdk_disable(self):
|
||||
self.env["SPOTIFLAC_DISCORD_SDK"] = "0"
|
||||
result = self.run_build("--production")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
calls = self.calls()
|
||||
build = next(call for call in calls if call["args"][:2] == ["build", "apk"])
|
||||
self.assertEqual(build["sdk"], "1")
|
||||
self.assertNotIn("--production", build["args"])
|
||||
self.assertTrue(all("--discord-sdk" in call["args"] for call in calls if call["tool"] == "audit"))
|
||||
|
||||
def test_production_rejects_lite_in_either_argument_order(self):
|
||||
for arguments in (("--production", "--lite"), ("--lite", "--production")):
|
||||
result = self.run_build(*arguments)
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("cannot be combined", result.stderr)
|
||||
self.assertFalse(self.log.exists())
|
||||
|
||||
def test_production_missing_sdk_components_stops_before_flutter(self):
|
||||
sdk = self.project / "third_party/spotiflac_discord/sdk"
|
||||
for name in (
|
||||
"discord_partner_sdk.aar", "notices/Discord-License-Notices.txt",
|
||||
"android/prefab/modules/discord_partner_sdk/include/discordpp.h",
|
||||
"android/jni/arm64-v8a/libdiscord_partner_sdk.so",
|
||||
"android/jni/armeabi-v7a/libdiscord_partner_sdk.so",
|
||||
):
|
||||
with self.subTest(component=name):
|
||||
path = sdk / name
|
||||
data = path.read_bytes()
|
||||
path.unlink()
|
||||
result = self.run_build("--production")
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("production requires", result.stderr)
|
||||
path.write_bytes(data)
|
||||
self.assertFalse(self.log.exists())
|
||||
|
||||
def test_wrong_flutter_version_stops_before_build_or_audit(self):
|
||||
self.env["BUILD_TEST_FLUTTER_VERSION"] = "0.0.0"
|
||||
result = self.run_build()
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("Flutter 3.47.5 is required", result.stderr)
|
||||
self.assertEqual(len(self.calls()), 1)
|
||||
|
||||
def test_invalid_or_overridden_abis_stop_before_flutter(self):
|
||||
for abis in ("", "x86_64", "arm64-v8a,arm64-v8a", "armeabi-v7a, arm64-v8a"):
|
||||
with self.subTest(abis=abis):
|
||||
self.env["SPOTIFLAC_RUST_ANDROID_ABIS"] = abis
|
||||
self.assertNotEqual(self.run_build().returncode, 0)
|
||||
self.env.pop("SPOTIFLAC_RUST_ANDROID_ABIS")
|
||||
self.assertNotEqual(self.run_build("--target-platform=android-x64").returncode, 0)
|
||||
self.assertFalse(self.log.exists())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+11
@@ -23,6 +23,17 @@ in Android assets and iOS resources. Without these files the app still builds, b
|
||||
the presence setting reports that the SDK is unavailable. A clean clone alone
|
||||
does not produce a Discord-enabled build.
|
||||
|
||||
To deliberately omit a staged SDK, set `SPOTIFLAC_DISCORD_SDK=0` during Android
|
||||
builds or iOS `pod install` and app builds. `bash scripts/build_android.sh --lite`
|
||||
sets this flag for Android. The bridge remains registered and reports presence
|
||||
as unavailable; the staged SDK files are retained for subsequent full builds.
|
||||
|
||||
Production Android builds use `bash scripts/build_android.sh --production`,
|
||||
which forces Discord on, checks the staged SDK and audits it in every APK ABI.
|
||||
`--production --lite` is rejected. Release CI requires the SDK on both platforms
|
||||
and stops before publication if the SDK is absent. Provision the official SDK
|
||||
in the build environment before running that workflow.
|
||||
|
||||
Android uses the installed Discord app's signed-in session (Social SDK 1.10+).
|
||||
The AAR and CMake use the same staged native library; the host packages one copy
|
||||
with `jniLibs.pickFirsts`. Microphone/Bluetooth permissions and the SDK voice
|
||||
|
||||
+2
-1
@@ -1,11 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
project(spotiflac_discord LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
option(SPOTIFLAC_DISCORD_SDK "Include the staged Discord Social SDK" ON)
|
||||
add_library(spotiflac_discord SHARED src/main/cpp/presence.cpp)
|
||||
target_compile_options(spotiflac_discord PRIVATE -Wall -Wextra -Werror -fvisibility=hidden)
|
||||
target_link_options(spotiflac_discord PRIVATE "-Wl,-z,max-page-size=16384")
|
||||
set(SDK "${CMAKE_CURRENT_SOURCE_DIR}/../sdk/android")
|
||||
if(EXISTS "${SDK}/jni/${ANDROID_ABI}/libdiscord_partner_sdk.so")
|
||||
if(SPOTIFLAC_DISCORD_SDK AND EXISTS "${SDK}/jni/${ANDROID_ABI}/libdiscord_partner_sdk.so")
|
||||
add_library(discord_partner_sdk SHARED IMPORTED)
|
||||
set_target_properties(discord_partner_sdk PROPERTIES IMPORTED_LOCATION
|
||||
"${SDK}/jni/${ANDROID_ABI}/libdiscord_partner_sdk.so")
|
||||
|
||||
+7
-2
@@ -4,13 +4,18 @@ version '1.0'
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
def discordSdkEnabled = System.getenv('SPOTIFLAC_DISCORD_SDK') != '0'
|
||||
|
||||
android {
|
||||
namespace 'com.zarz.spotiflac.discord'
|
||||
compileSdk 37
|
||||
defaultConfig {
|
||||
minSdk 24
|
||||
externalNativeBuild {
|
||||
cmake { arguments '-DANDROID_STL=c++_static' }
|
||||
cmake {
|
||||
arguments '-DANDROID_STL=c++_static',
|
||||
"-DSPOTIFLAC_DISCORD_SDK=${discordSdkEnabled ? 'ON' : 'OFF'}"
|
||||
}
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
@@ -18,7 +23,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_25
|
||||
}
|
||||
kotlinOptions { jvmTarget = '25' }
|
||||
sourceSets.main.assets.srcDir('../sdk/notices')
|
||||
if (discordSdkEnabled) sourceSets.main.assets.srcDir('../sdk/notices')
|
||||
externalNativeBuild {
|
||||
cmake { path 'CMakeLists.txt'; version '3.22.1' }
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency 'Flutter'
|
||||
s.platform = :ios, '16.0'
|
||||
sdk = 'Frameworks/discord_partner_sdk.xcframework'
|
||||
if File.directory?(File.join(__dir__, sdk))
|
||||
if ENV['SPOTIFLAC_DISCORD_SDK'] != '0' && File.directory?(File.join(__dir__, sdk))
|
||||
s.vendored_frameworks = sdk
|
||||
s.resources = 'Frameworks/Discord-License-Notices.txt'
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
Reference in new issue
Block a user