Skip to content

Commit aa565cc

Browse files
jappeace-slothclaude
andcommitted
Remove haskellUseScrollDemo FFI and runtime app-switching mechanism
The useScrollDemo JNI method + haskellUseScrollDemo FFI export were test infrastructure that leaked into the core library bridge, forcing every app that replaces App.hs to either export the symbol or work around the linker error. Fix: build the scroll-demo test APK/simulator-app with test/ScrollDemoMain.hs as the entry point so the app starts directly in scroll-demo mode. No runtime switching is needed, so the whole mechanism can be deleted: - cbits/jni_bridge.c: remove useScrollDemo JNI method - src/HaskellMobile/App.hs: remove haskellUseScrollDemo foreign export - android/java/.../MainActivity.java: remove native useScrollDemo() and the test_mode intent check - include/HaskellMobile.h: remove haskellUseScrollDemo declaration - ios/HaskellMobile/HaskellBridge.swift: remove useScrollDemo() wrapper - ios/HaskellMobile/ContentView.swift: remove --scroll-demo flag handling - nix/emulator-scroll.nix: build scroll APK with ScrollDemoMain.hs - nix/simulator-scroll.nix: build scroll simulator app with ScrollDemoMain.hs - test/ScrollDemoMain.hs: new entry point using scrollDemoApp directly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0dd6fa8 commit aa565cc

9 files changed

Lines changed: 42 additions & 46 deletions

File tree

‎android/java/me/jappie/haskellmobile/MainActivity.java‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class MainActivity extends Activity implements View.OnClickListener {
1414
}
1515

1616
private native String greet(String name);
17-
private native void useScrollDemo();
1817
private native void renderUI();
1918
private native void onButtonClick(View view);
2019
private native void onTextChange(View view, String text);
@@ -30,10 +29,6 @@ public class MainActivity extends Activity implements View.OnClickListener {
3029
protected void onCreate(Bundle savedInstanceState) {
3130
super.onCreate(savedInstanceState);
3231
onLifecycleCreate();
33-
String testMode = getIntent().getStringExtra("test_mode");
34-
if ("scroll_demo".equals(testMode)) {
35-
useScrollDemo();
36-
}
3732
// Render UI from Haskell instead of XML layout
3833
renderUI();
3934
}

‎cbits/jni_bridge.c‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ extern void haskellOnLifecycle(void *ctx, int eventType);
2424
extern void haskellRenderUI(void *ctx);
2525
extern void haskellOnUIEvent(void *ctx, int callbackId);
2626
extern void haskellOnUITextChange(void *ctx, int callbackId, const char *text);
27-
extern void haskellUseScrollDemo(void);
2827

2928
/* Android UI bridge (from ui_bridge_android.c) */
3029
extern void setup_android_ui_bridge(JNIEnv *env, jobject activity, void *haskellCtx);
@@ -77,13 +76,6 @@ JNI_METHOD(greet)(JNIEnv *env, jobject thiz, jstring jname)
7776

7877
/* --- UI bridge JNI methods --- */
7978

80-
JNIEXPORT void JNICALL
81-
JNI_METHOD(useScrollDemo)(JNIEnv *env, jobject obj)
82-
{
83-
(void)env; (void)obj;
84-
haskellUseScrollDemo();
85-
}
86-
8779
JNIEXPORT void JNICALL
8880
JNI_METHOD(renderUI)(JNIEnv *env, jobject thiz)
8981
{

‎include/HaskellMobile.h‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,5 @@ void haskellRenderUI(void *ctx);
4646
* ctx must be a pointer returned by haskellCreateContext(). */
4747
void haskellOnUIEvent(void *ctx, int32_t callbackId);
4848

49-
/* Switch the running app to the scroll demo.
50-
* Called by test harnesses to exercise the ScrollView widget end-to-end. */
51-
void haskellUseScrollDemo(void);
5249

5350
#endif /* HASKELL_MOBILE_H */

‎ios/HaskellMobile/ContentView.swift‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ struct HaskellUIView: UIViewControllerRepresentable {
1010
let ptr = Unmanaged.passUnretained(vc).toOpaque()
1111
setup_ios_ui_bridge(ptr, HaskellBridge.getContext())
1212

13-
if CommandLine.arguments.contains("--scroll-demo") {
14-
HaskellBridge.useScrollDemo()
15-
}
16-
1713
HaskellBridge.renderUI()
1814

1915
// CI auto-test: simulate button tap 3s after the initial render.

‎ios/HaskellMobile/HaskellBridge.swift‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,4 @@ class HaskellBridge {
5050
return context
5151
}
5252

53-
/// Switch the running app to the scroll demo.
54-
/// Call before renderUI() to exercise ScrollView end-to-end in integration tests.
55-
static func useScrollDemo() {
56-
haskellUseScrollDemo()
57-
}
5853
}

‎nix/emulator-scroll.nix‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Android emulator ScrollView integration test.
22
#
3-
# Boots an emulator, installs the APK in scroll-demo mode, and verifies:
3+
# Builds the APK with ScrollDemoMain.hs as the entry point so the app starts
4+
# directly in scroll-demo mode — no runtime switching needed. Verifies:
45
# 1. Haskell emitted a ScrollView node (logcat: createNode type=5)
56
# 2. Native view hierarchy contains android.widget.ScrollView (uiautomator)
67
# 3. Swiping up reveals the "Reached Bottom" button (uiautomator after swipe)
@@ -18,7 +19,14 @@ let
1819
config.android_sdk.accept_license = true;
1920
};
2021

21-
apk = import ./apk.nix { inherit sources; };
22+
lib = import ./lib.nix { inherit sources; };
23+
scrollAndroid = import ./android.nix { inherit sources; mainModule = ../test/ScrollDemoMain.hs; };
24+
apk = lib.mkApk {
25+
sharedLib = scrollAndroid;
26+
androidSrc = ../android;
27+
apkName = "haskell-mobile-scroll.apk";
28+
name = "haskell-mobile-scroll-apk";
29+
};
2230

2331
androidComposition = pkgs.androidenv.composeAndroidPackages {
2432
platformVersions = [ "34" ];
@@ -230,9 +238,9 @@ echo "APK installed."
230238
echo "=== Preparing logcat ==="
231239
"$ADB" -s "emulator-$PORT" logcat -c
232240
233-
# --- Launch activity with scroll_demo intent extra ---
234-
echo "=== Launching $PACKAGE/$ACTIVITY in scroll-demo mode ==="
235-
"$ADB" -s "emulator-$PORT" shell am start -n "$PACKAGE/$ACTIVITY" --es test_mode scroll_demo
241+
# --- Launch activity ---
242+
echo "=== Launching $PACKAGE/$ACTIVITY ==="
243+
"$ADB" -s "emulator-$PORT" shell am start -n "$PACKAGE/$ACTIVITY"
236244
237245
# --- Wait for initial render ---
238246
echo "=== Waiting for initial render (timeout: 120s) ==="

‎nix/simulator-scroll.nix‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# iOS Simulator ScrollView integration test.
22
#
3-
# Builds and installs the app with --scroll-demo --autotest, then verifies:
3+
# Builds the app with ScrollDemoMain.hs as the entry point so the app starts
4+
# directly in scroll-demo mode, then verifies:
45
# 1. Haskell emitted a ScrollView node (os_log: createNode(type=5))
56
# 2. The "Reached Bottom" button callback fired (os_log: Click dispatched: callbackId=0)
67
#
7-
# The --scroll-demo flag switches the app to scrollDemoApp before the first render.
88
# The --autotest flag fires event 0 (the "Reached Bottom" button) 3s after render.
99
#
1010
# Independent from other simulator tests — can run in parallel.
@@ -16,7 +16,13 @@
1616
let
1717
pkgs = import sources.nixpkgs {};
1818

19-
simulatorApp = import ./simulator-app.nix { inherit sources; };
19+
scrollIos = import ./ios.nix { inherit sources; mainModule = ../test/ScrollDemoMain.hs; simulator = true; };
20+
simulatorApp = lib.mkSimulatorApp {
21+
iosLib = scrollIos;
22+
iosSrc = ../ios;
23+
name = "haskell-mobile-scroll-simulator-app";
24+
};
25+
lib = import ./lib.nix { inherit sources; };
2026

2127
xcodegen = pkgs.xcodegen;
2228

@@ -174,9 +180,9 @@ LOG_PID=$!
174180
# Give log stream time to fully attach before launching
175181
sleep 5
176182
177-
# --- Launch app with --scroll-demo --autotest ---
178-
echo "=== Launching $BUNDLE_ID with --scroll-demo --autotest ==="
179-
xcrun simctl launch "$SIM_UDID" "$BUNDLE_ID" --scroll-demo --autotest
183+
# --- Launch app with --autotest ---
184+
echo "=== Launching $BUNDLE_ID with --autotest ==="
185+
xcrun simctl launch "$SIM_UDID" "$BUNDLE_ID" --autotest
180186
181187
# --- Wait for initial render ---
182188
echo "=== Waiting for initial render (timeout: 60s) ==="
@@ -200,7 +206,7 @@ if [ $RENDER_DONE -eq 0 ]; then
200206
xcrun simctl terminate "$SIM_UDID" "$BUNDLE_ID" 2>/dev/null || true
201207
sleep 3
202208
> "$LOG_FILE"
203-
xcrun simctl launch "$SIM_UDID" "$BUNDLE_ID" --scroll-demo --autotest
209+
xcrun simctl launch "$SIM_UDID" "$BUNDLE_ID" --autotest
204210
205211
POLL_TIMEOUT=60
206212
POLL_ELAPSED=0

‎src/HaskellMobile/App.hs‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
{-# LANGUAGE ForeignFunctionInterface #-}
21
{-# LANGUAGE OverloadedStrings #-}
32
-- | Default implementation of the mobile app.
43
-- Provides 'loggingMobileContext' as the application context and a simple
54
-- counter demo as the default UI.
6-
module HaskellMobile.App (mobileApp, scrollDemoApp, haskellUseScrollDemo) where
5+
module HaskellMobile.App (mobileApp, scrollDemoApp) where
76

87
import Data.IORef (IORef, newIORef, readIORef, modifyIORef')
98
import Data.Text (pack)
10-
import HaskellMobile.Types (MobileApp(..), runMobileApp)
9+
import HaskellMobile.Types (MobileApp(..))
1110
import HaskellMobile.Lifecycle (loggingMobileContext)
1211
import HaskellMobile.Widget (Widget(..))
1312
import System.IO.Unsafe (unsafePerformIO)
@@ -53,9 +52,3 @@ scrollDemoView = pure $ ScrollView
5352
)
5453
]
5554

56-
-- | Switch the running app to the scroll demo. Called via JNI (Android) or
57-
-- direct FFI (iOS) when the test harness requests scroll-demo mode.
58-
haskellUseScrollDemo :: IO ()
59-
haskellUseScrollDemo = runMobileApp scrollDemoApp
60-
61-
foreign export ccall haskellUseScrollDemo :: IO ()

‎test/ScrollDemoMain.hs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
-- | Mobile entry point for the scroll-demo test app.
3+
--
4+
-- Used by the emulator and simulator ScrollView integration tests.
5+
-- Starts directly in scroll-demo mode so no runtime switching is needed.
6+
module Main where
7+
8+
import HaskellMobile (runMobileApp, platformLog)
9+
import HaskellMobile.App (scrollDemoApp)
10+
11+
main :: IO ()
12+
main = do
13+
runMobileApp scrollDemoApp
14+
platformLog "Scroll demo app registered"

0 commit comments

Comments
 (0)