Skip to content

Commit 95bee91

Browse files
cursoragentkubo6472
andcommitted
feat(ios): launch fixes, SideStore CI, and AltStore source
Runtime: - Fix main.dart/router.dart import cycle and GoRouter redirect blocking - Use app support storage on iOS (Android-only external storage) - Safe connectivity checks, update API timeouts, mobile init guards - Remote debug logging for future mobile diagnostics CI (upstream-compatible): - Restore full multi-platform debugbuild workflow - SideStore IPA packaging in MACOSIOS - AltStore source generation in DEPLOY (docs/altstore-source.json) - Drop fork-only OTA GitHub Pages flow Co-authored-by: Jakub Doboš <kubo6472@users.noreply.github.com>
1 parent 86130d0 commit 95bee91

28 files changed

Lines changed: 1390 additions & 247 deletions

.github/workflows/debugbuild.yml

Lines changed: 167 additions & 113 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ You can build the app in either release or debug mode. If you're building it in
8686
flutter build ios --<INSERT MODE>
8787
```
8888

89+
## iOS install via SideStore / AltStore
90+
91+
CI builds an IPA on each deploy, packages it for SideStore (correct `Payload/` zip layout + ad-hoc `codesign` on macOS), and regenerates an [AltStore source](https://faq.altstore.io/developers/make-a-source) at `docs/altstore-source.json` from **all** GitHub Releases, including pre-releases.
92+
93+
**Source URL** (add once in SideStore or AltStore):
94+
95+
`https://github.com/floatyfp/floaty/blob/release/docs/altstore-source.json?raw=true`
96+
97+
(or the equivalent raw URL for your fork/branch)
98+
99+
Edit static metadata in `docs/altstore-source.meta.json`; version entries are filled automatically from release assets (`floaty-*-ios.ipa`).
100+
89101
- **Windows**
90102
```bash
91103
flutter build windows --<INSERT MODE>

docs/altstore-source.json

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
{
2+
"name": "Floaty",
3+
"subtitle": "Open-source Floatplane client for iOS",
4+
"description": "Floaty builds for iOS from GitHub Releases. Includes pre-releases from nightly, beta, and development branches. IPAs are packaged for SideStore and AltStore.",
5+
"iconURL": "https://floaty.fyi/assets/floaty.png",
6+
"website": "https://floaty.fyi",
7+
"tintColor": "#3b82f6",
8+
"featuredApps": [
9+
"uk.bw86.floaty"
10+
],
11+
"news": [],
12+
"apps": [
13+
{
14+
"name": "Floaty",
15+
"bundleIdentifier": "uk.bw86.floaty",
16+
"developerName": "Floaty",
17+
"subtitle": "Floatplane client for iOS",
18+
"localizedDescription": "An open-source Floatplane client. Install via SideStore or AltStore; pick a build matching your branch (release, beta, nightly, or development).",
19+
"iconURL": "https://floaty.fyi/assets/floaty.png",
20+
"tintColor": "#3b82f6",
21+
"category": "entertainment",
22+
"screenshots": [],
23+
"appPermissions": {
24+
"entitlements": [],
25+
"privacy": {}
26+
},
27+
"patreon": {},
28+
"versions": [
29+
{
30+
"version": "0.0.22",
31+
"buildVersion": "22",
32+
"marketingVersion": "0.0.22 (22)",
33+
"date": "2026-06-03T08:00:24Z",
34+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.22-build22/floaty-0.0.22-ios.ipa",
35+
"size": 24517758,
36+
"localizedDescription": "[main] ## main iOS build"
37+
},
38+
{
39+
"version": "0.0.21",
40+
"buildVersion": "21",
41+
"marketingVersion": "0.0.21 (21)",
42+
"date": "2026-06-03T05:45:36Z",
43+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.21-build21/floaty-0.0.21-ios.ipa",
44+
"size": 24517762,
45+
"localizedDescription": "[main] ## main iOS build"
46+
},
47+
{
48+
"version": "0.0.20",
49+
"buildVersion": "20",
50+
"marketingVersion": "0.0.20 (20)",
51+
"date": "2026-06-01T13:37:19Z",
52+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.20-build20/floaty-0.0.20-ios.ipa",
53+
"size": 24544867,
54+
"localizedDescription": "[main] ## main iOS build"
55+
},
56+
{
57+
"version": "0.0.19",
58+
"buildVersion": "19",
59+
"marketingVersion": "0.0.19 (19)",
60+
"date": "2026-06-01T13:30:22Z",
61+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.19-build19/floaty-0.0.19-ios.ipa",
62+
"size": 24946293,
63+
"localizedDescription": "[main] ## main iOS build"
64+
},
65+
{
66+
"version": "0.0.17",
67+
"buildVersion": "17",
68+
"marketingVersion": "0.0.17 (17)",
69+
"date": "2026-06-01T12:21:56Z",
70+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-altstore-duplicate-versions-81e9-v0.0.17-build17/floaty-0.0.17-ios.ipa",
71+
"size": 24940996,
72+
"localizedDescription": "[cursor/fix-altstore-duplicate-versions-81e9] ## cursor/fix-altstore-duplicate-versions-81e9 iOS build"
73+
},
74+
{
75+
"version": "0.0.16",
76+
"buildVersion": "16",
77+
"marketingVersion": "0.0.16 (16)",
78+
"date": "2026-06-01T11:31:59Z",
79+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-altstore-duplicate-versions-81e9-v0.0.16-build16/floaty-0.0.16-ios.ipa",
80+
"size": 24941003,
81+
"localizedDescription": "[cursor/fix-altstore-duplicate-versions-81e9] ## cursor/fix-altstore-duplicate-versions-81e9 iOS build"
82+
},
83+
{
84+
"version": "0.0.15",
85+
"buildVersion": "15",
86+
"marketingVersion": "0.0.15 (15)",
87+
"date": "2026-06-01T10:36:43Z",
88+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/altstore-source-github-pages-81e9-v0.0.15-build15/floaty-0.0.15-ios.ipa",
89+
"size": 24941018,
90+
"localizedDescription": "[cursor/altstore-source-github-pages-81e9] ## cursor/altstore-source-github-pages-81e9 iOS build"
91+
},
92+
{
93+
"version": "0.0.14",
94+
"buildVersion": "14",
95+
"marketingVersion": "0.0.14 (14)",
96+
"date": "2026-06-01T09:25:03Z",
97+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ios-ipa-sidestore-packaging-81e9-v0.0.14-build14/floaty-0.0.14-ios.ipa",
98+
"size": 24464495,
99+
"localizedDescription": "[cursor/fix-ios-ipa-sidestore-packaging-81e9] ## cursor/fix-ios-ipa-sidestore-packaging-81e9 iOS build\r"
100+
},
101+
{
102+
"version": "0.0.13",
103+
"buildVersion": "13",
104+
"marketingVersion": "0.0.13 (13)",
105+
"date": "2026-05-17T18:23:04Z",
106+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ota-manifest-plist-367d-v0.0.13-build13/floaty-0.0.13-ios.ipa",
107+
"size": 24469024,
108+
"localizedDescription": "[cursor/fix-ota-manifest-plist-367d] ## cursor/fix-ota-manifest-plist-367d iOS build\r"
109+
},
110+
{
111+
"version": "0.0.12",
112+
"buildVersion": "12",
113+
"marketingVersion": "0.0.12 (12)",
114+
"date": "2026-05-17T17:26:18Z",
115+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ota-manifest-plist-367d-v0.0.12-build12/floaty-0.0.12-ios.ipa",
116+
"size": 24469026,
117+
"localizedDescription": "[cursor/fix-ota-manifest-plist-367d] ## cursor/fix-ota-manifest-plist-367d iOS build"
118+
},
119+
{
120+
"version": "0.0.11",
121+
"buildVersion": "11",
122+
"marketingVersion": "0.0.11 (11)",
123+
"date": "2026-05-17T17:10:22Z",
124+
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ios-versioning-ota-6e6e-v0.0.11-build11/floaty-0.0.11-ios.ipa",
125+
"size": 24468788,
126+
"localizedDescription": "[cursor/fix-ios-versioning-ota-6e6e] ## cursor/fix-ios-versioning-ota-6e6e iOS build"
127+
}
128+
]
129+
}
130+
]
131+
}

docs/altstore-source.meta.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "Floaty",
3+
"subtitle": "Open-source Floatplane client for iOS",
4+
"description": "Floaty builds for iOS from GitHub Releases. Includes pre-releases from nightly, beta, and development branches. IPAs are packaged for SideStore and AltStore.",
5+
"iconURL": "https://floaty.fyi/assets/floaty.png",
6+
"website": "https://floaty.fyi",
7+
"tintColor": "#3b82f6",
8+
"featuredApps": ["uk.bw86.floaty"],
9+
"news": [],
10+
"app": {
11+
"name": "Floaty",
12+
"bundleIdentifier": "uk.bw86.floaty",
13+
"developerName": "Floaty",
14+
"subtitle": "Floatplane client for iOS",
15+
"localizedDescription": "An open-source Floatplane client. Install via SideStore or AltStore; pick a build matching your branch (release, beta, nightly, or development).",
16+
"iconURL": "https://floaty.fyi/assets/floaty.png",
17+
"tintColor": "#3b82f6",
18+
"category": "entertainment",
19+
"screenshots": [],
20+
"appPermissions": {
21+
"entitlements": [],
22+
"privacy": {}
23+
},
24+
"patreon": {}
25+
}
26+
}

docs/remote-debug-logging.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Remote debug logging
2+
3+
Floaty can mirror app logs and uncaught Flutter/Dart errors to an external HTTP
4+
endpoint for debugging white-screen or startup issues.
5+
6+
Remote logging is off by default. Enable it at build or run time with Dart
7+
defines:
8+
9+
```sh
10+
flutter run -d linux \
11+
--dart-define=FLOATY_REMOTE_LOG_ENDPOINT=https://example.com/floaty-logs
12+
```
13+
14+
If the endpoint requires bearer auth, also pass:
15+
16+
```sh
17+
--dart-define=FLOATY_REMOTE_LOG_TOKEN=your-token
18+
```
19+
20+
The app sends JSON payloads with a session id, timestamp, platform, level, and
21+
message. The developer logs screen can also upload the currently selected app or
22+
download log view on demand.
23+
24+
Before logs are saved or sent, common authorization, token, and cookie patterns
25+
are redacted.

lib/app/flavor_theme.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import 'package:flutter/material.dart';
2+
3+
/// Set during [main] before [runApp]. Used by theme and settings UI.
4+
late final Color? flavorPrimary;

lib/features/discordrpc/controllers/discord_rpc_controller.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import 'package:flutter_discord_rpc/flutter_discord_rpc.dart';
55
import 'package:package_info_plus/package_info_plus.dart';
66
import 'package:get_it/get_it.dart';
77

8+
import 'platform_check_stub.dart' if (dart.library.io) 'platform_check_io.dart'
9+
as platform_check;
10+
811
final discordRPCController = GetIt.I<DiscordRPCController>();
12+
bool get isDiscordRPCSupported => platform_check.isDiscordRPCSupported;
913

1014
class DiscordRPCController {
1115
bool initialized = false;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import 'dart:io' show Platform;
2+
3+
bool get isDiscordRPCSupported => Platform.isWindows || Platform.isLinux;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bool get isDiscordRPCSupported => false;

lib/features/download/controllers/fp_download_service.dart

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ import 'package:floaty/features/download/controllers/download_log.dart';
1515
import 'package:floaty/features/download/controllers/fp_download_url_helper.dart';
1616
import 'package:floaty/features/api/models/definitions.dart';
1717

18+
Directory selectOfflineStorageDirectory({
19+
required Directory applicationSupportDirectory,
20+
required bool useExternalStorage,
21+
Directory? externalStorageDirectory,
22+
}) {
23+
if (useExternalStorage && externalStorageDirectory != null) {
24+
return externalStorageDirectory;
25+
}
26+
return applicationSupportDirectory;
27+
}
28+
1829
/// Floatplane Download Service - UI client for the FP download isolate
1930
class FPDownloadService {
2031
static final FPDownloadService _instance = FPDownloadService._internal();
@@ -57,13 +68,15 @@ class FPDownloadService {
5768

5869
// Setup offline directory - ALWAYS use app's internal storage for offline library
5970
// The custom download_path is only for external downloads (useExternalPath=true)
60-
Directory? directory;
61-
if (Platform.isAndroid || Platform.isIOS) {
62-
directory = await getExternalStorageDirectory();
63-
} else {
64-
directory = await getApplicationSupportDirectory();
65-
}
66-
_offlinePath = p.join(directory?.path ?? '', 'floatplane_offline');
71+
final appSupportDirectory = await getApplicationSupportDirectory();
72+
final externalStorageDirectory =
73+
Platform.isAndroid ? await getExternalStorageDirectory() : null;
74+
final directory = selectOfflineStorageDirectory(
75+
applicationSupportDirectory: appSupportDirectory,
76+
externalStorageDirectory: externalStorageDirectory,
77+
useExternalStorage: Platform.isAndroid,
78+
);
79+
_offlinePath = p.join(directory.path, 'floatplane_offline');
6780
await Directory(_offlinePath!).create(recursive: true);
6881
_logger!.log(
6982
'[FPDownloadService] Offline library path (internal): $_offlinePath');
@@ -104,6 +117,16 @@ class FPDownloadService {
104117

105118
Future<void> _initNotifications() async {
106119
try {
120+
final dbusSessionBusAddress =
121+
Platform.environment['DBUS_SESSION_BUS_ADDRESS'];
122+
if (Platform.isLinux &&
123+
(dbusSessionBusAddress == null || dbusSessionBusAddress.isEmpty)) {
124+
_logger?.log(
125+
'[FPDownloadService] Skipping notifications; D-Bus session bus is unavailable');
126+
_notificationsInitialized = false;
127+
return;
128+
}
129+
107130
const androidSettings =
108131
AndroidInitializationSettings('@mipmap/ic_launcher');
109132
const iosSettings = DarwinInitializationSettings(

0 commit comments

Comments
 (0)