Compare commits

...

3 Commits

Author SHA1 Message Date
zarzet db335f5ba6 chore: bump version to 1.0.3 2026-01-01 20:36:02 +07:00
zarzet ab9869a849 fix: add XCFramework to Xcode project dynamically for iOS build 2026-01-01 20:35:10 +07:00
zarzet 34791310b7 fix: remove empty assets/icons folder reference 2026-01-01 20:25:53 +07:00
5 changed files with 127 additions and 50 deletions
+40 -4
View File
@@ -38,10 +38,46 @@ jobs:
echo "=== Checking XCFramework ===" echo "=== Checking XCFramework ==="
ls -la ios/Frameworks/ ls -la ios/Frameworks/
ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1) ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1)
echo "=== Debug.xcconfig ==="
cat ios/Flutter/Debug.xcconfig - name: Add XCFramework to Xcode project
echo "=== Release.xcconfig ===" run: |
cat ios/Flutter/Release.xcconfig # Install xcodeproj gem for modifying Xcode project
sudo gem install xcodeproj
# Create Ruby script to add framework
cat > add_framework.rb << 'EOF'
require 'xcodeproj'
project_path = 'ios/Runner.xcodeproj'
project = Xcodeproj::Project.open(project_path)
# Get the main target
target = project.targets.find { |t| t.name == 'Runner' }
# Get or create Frameworks group
frameworks_group = project.main_group.find_subpath('Frameworks', true)
frameworks_group ||= project.main_group.new_group('Frameworks')
# Add XCFramework reference
framework_path = 'Frameworks/Gobackend.xcframework'
framework_ref = frameworks_group.new_file(framework_path, :project)
# Add to frameworks build phase
frameworks_build_phase = target.frameworks_build_phase
frameworks_build_phase.add_file_reference(framework_ref)
# Add to embed frameworks build phase
embed_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase) && p.name == 'Embed Frameworks' }
if embed_phase
build_file = embed_phase.add_file_reference(framework_ref)
build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy', 'RemoveHeadersOnCopy'] }
end
project.save
puts "Successfully added Gobackend.xcframework to Xcode project"
EOF
ruby add_framework.rb
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@v2
+82 -40
View File
@@ -12,17 +12,14 @@ on:
default: 'v1.0.0' default: 'v1.0.0'
jobs: jobs:
build-android: # Get version first (quick job)
get-version:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
version: ${{ steps.get_version.outputs.version }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Get version - name: Get version
id: get_version id: version
run: | run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
@@ -30,6 +27,15 @@ jobs:
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
fi fi
# Android and iOS build in PARALLEL
build-android:
runs-on: ubuntu-latest
needs: get-version
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@@ -42,6 +48,16 @@ jobs:
go-version: '1.21' go-version: '1.21'
cache-dependency-path: go_backend/go.sum cache-dependency-path: go_backend/go.sum
# Cache Gradle for faster builds
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- name: Install Android SDK & NDK - name: Install Android SDK & NDK
uses: android-actions/setup-android@v3 uses: android-actions/setup-android@v3
@@ -75,12 +91,10 @@ jobs:
- name: Rename APKs - name: Rename APKs
run: | run: |
VERSION=${{ steps.get_version.outputs.version }} VERSION=${{ needs.get-version.outputs.version }}
cd build/app/outputs/flutter-apk cd build/app/outputs/flutter-apk
# Rename split APKs
mv app-arm64-v8a-release.apk SpotiFLAC-${VERSION}-arm64.apk || true mv app-arm64-v8a-release.apk SpotiFLAC-${VERSION}-arm64.apk || true
mv app-armeabi-v7a-release.apk SpotiFLAC-${VERSION}-arm32.apk || true mv app-armeabi-v7a-release.apk SpotiFLAC-${VERSION}-arm32.apk || true
# Also rename universal if exists
mv app-release.apk SpotiFLAC-${VERSION}-universal.apk || true mv app-release.apk SpotiFLAC-${VERSION}-universal.apk || true
ls -la ls -la
@@ -92,7 +106,7 @@ jobs:
build-ios: build-ios:
runs-on: macos-latest runs-on: macos-latest
needs: build-android needs: get-version # Only depends on version, NOT android build!
steps: steps:
- name: Checkout repository - name: Checkout repository
@@ -104,6 +118,14 @@ jobs:
go-version: '1.21' go-version: '1.21'
cache-dependency-path: go_backend/go.sum cache-dependency-path: go_backend/go.sum
# Cache CocoaPods
- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: ios/Pods
key: pods-${{ runner.os }}-${{ hashFiles('ios/Podfile.lock') }}
restore-keys: pods-${{ runner.os }}-
- name: Install gomobile - name: Install gomobile
run: | run: |
go install golang.org/x/mobile/cmd/gomobile@latest go install golang.org/x/mobile/cmd/gomobile@latest
@@ -119,13 +141,48 @@ jobs:
- name: Verify XCFramework created - name: Verify XCFramework created
run: | run: |
echo "=== Checking XCFramework ==="
ls -la ios/Frameworks/ ls -la ios/Frameworks/
ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1) ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1)
echo "=== Debug.xcconfig ==="
cat ios/Flutter/Debug.xcconfig - name: Add XCFramework to Xcode project
echo "=== Release.xcconfig ===" run: |
cat ios/Flutter/Release.xcconfig # Install xcodeproj gem for modifying Xcode project
sudo gem install xcodeproj
# Create Ruby script to add framework
cat > add_framework.rb << 'EOF'
require 'xcodeproj'
project_path = 'ios/Runner.xcodeproj'
project = Xcodeproj::Project.open(project_path)
# Get the main target
target = project.targets.find { |t| t.name == 'Runner' }
# Get or create Frameworks group
frameworks_group = project.main_group.find_subpath('Frameworks', true)
frameworks_group ||= project.main_group.new_group('Frameworks')
# Add XCFramework reference
framework_path = 'Frameworks/Gobackend.xcframework'
framework_ref = frameworks_group.new_file(framework_path, :project)
# Add to frameworks build phase
frameworks_build_phase = target.frameworks_build_phase
frameworks_build_phase.add_file_reference(framework_ref)
# Add to embed frameworks build phase
embed_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase) && p.name == 'Embed Frameworks' }
if embed_phase
build_file = embed_phase.add_file_reference(framework_ref)
build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy', 'RemoveHeadersOnCopy'] }
end
project.save
puts "Successfully added Gobackend.xcframework to Xcode project"
EOF
ruby add_framework.rb
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@v2
@@ -144,7 +201,7 @@ jobs:
- name: Create IPA - name: Create IPA
run: | run: |
VERSION=${{ needs.build-android.outputs.version }} VERSION=${{ needs.get-version.outputs.version }}
mkdir -p build/ios/ipa mkdir -p build/ios/ipa
cd build/ios/iphoneos cd build/ios/iphoneos
mkdir Payload mkdir Payload
@@ -160,14 +217,11 @@ jobs:
create-release: create-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-android, build-ios] needs: [get-version, build-android, build-ios]
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download Android APK - name: Download Android APK
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
@@ -183,34 +237,22 @@ jobs:
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
tag_name: ${{ needs.build-android.outputs.version }} tag_name: ${{ needs.get-version.outputs.version }}
name: SpotiFLAC ${{ needs.build-android.outputs.version }} name: SpotiFLAC ${{ needs.get-version.outputs.version }}
body: | body: |
## SpotiFLAC ${{ needs.build-android.outputs.version }} ## SpotiFLAC ${{ needs.get-version.outputs.version }}
Download Spotify tracks in FLAC quality from Tidal, Qobuz & Amazon Music. Download Spotify tracks in FLAC quality from Tidal, Qobuz & Amazon Music.
### Downloads ### Downloads
- **Android (arm64)**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-arm64.apk` (recommended for most devices) - **Android (arm64)**: `SpotiFLAC-${{ needs.get-version.outputs.version }}-arm64.apk` (recommended)
- **Android (arm32)**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-arm32.apk` (for older devices) - **Android (arm32)**: `SpotiFLAC-${{ needs.get-version.outputs.version }}-arm32.apk` (older devices)
- **iOS**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-ios-unsigned.ipa` (requires sideloading) - **iOS**: `SpotiFLAC-${{ needs.get-version.outputs.version }}-ios-unsigned.ipa` (sideload required)
### Features
- Search Spotify tracks, albums, and playlists
- Download in FLAC quality from multiple sources
- Automatic fallback to available services
- Embedded metadata and cover art
- Lyrics support (synced and plain)
- Material 3 Expressive UI with dynamic colors
### Installation ### Installation
**Android**: Enable "Install from unknown sources" and install the APK **Android**: Enable "Install from unknown sources" and install the APK
**iOS**: Use AltStore, Sideloadly, or similar tools to sideload the IPA **iOS**: Use AltStore, Sideloadly, or similar tools to sideload the IPA
files: ./release/*
---
*Note: iOS IPA is unsigned and requires sideloading*
files: |
./release/*
draft: false draft: false
prerelease: false prerelease: false
env: env:
+2 -2
View File
@@ -132,11 +132,11 @@ class SettingsScreen extends ConsumerWidget {
ListTile( ListTile(
leading: Icon(Icons.info, color: colorScheme.primary), leading: Icon(Icons.info, color: colorScheme.primary),
title: const Text('About'), title: const Text('About'),
subtitle: const Text('SpotiFLAC v1.0.2'), subtitle: const Text('SpotiFLAC v1.0.3'),
onTap: () => showAboutDialog( onTap: () => showAboutDialog(
context: context, context: context,
applicationName: 'SpotiFLAC', applicationName: 'SpotiFLAC',
applicationVersion: '1.0.2', applicationVersion: '1.0.3',
applicationLegalese: '© 2024 SpotiFLAC', applicationLegalese: '© 2024 SpotiFLAC',
), ),
), ),
+2 -2
View File
@@ -139,11 +139,11 @@ class _SettingsTabState extends ConsumerState<SettingsTab> with AutomaticKeepAli
ListTile( ListTile(
leading: Icon(Icons.info, color: colorScheme.primary), leading: Icon(Icons.info, color: colorScheme.primary),
title: const Text('About'), title: const Text('About'),
subtitle: const Text('SpotiFLAC v1.0.2'), subtitle: const Text('SpotiFLAC v1.0.3'),
onTap: () => showAboutDialog( onTap: () => showAboutDialog(
context: context, context: context,
applicationName: 'SpotiFLAC', applicationName: 'SpotiFLAC',
applicationVersion: '1.0.2', applicationVersion: '1.0.3',
applicationLegalese: '© 2024 SpotiFLAC', applicationLegalese: '© 2024 SpotiFLAC',
), ),
), ),
+1 -2
View File
@@ -1,7 +1,7 @@
name: spotiflac_android name: spotiflac_android
description: Download Spotify tracks in FLAC from Tidal, Qobuz & Amazon Music description: Download Spotify tracks in FLAC from Tidal, Qobuz & Amazon Music
publish_to: 'none' publish_to: 'none'
version: 1.0.2+3 version: 1.0.3+4
environment: environment:
sdk: ^3.10.0 sdk: ^3.10.0
@@ -75,4 +75,3 @@ flutter:
assets: assets:
- assets/images/ - assets/images/
- assets/icons/