Home Blog

ChatGPT helps velocity up affected person screening for medical trials – NanoApps Medical – Official web site


A brand new examine within the tutorial journal Machine Studying: Well being discovers that ChatGPT can speed up affected person screening for medical trials, exhibiting promise in decreasing delays and bettering trial success charges.

Researchers at UT Southwestern Medical Centre used ChatGPT to evaluate whether or not sufferers have been eligible to participate in medical trials and have been in a position to determine appropriate candidates inside minutes.

Scientific trials, which take a look at new drugs and procedures on the general public, are very important for creating and validating new therapies. However many trials battle to enrol sufficient members. In keeping with a current examine, as much as 20% of Nationwide Most cancers Institute (NCI)-affiliated trials fail as a result of low enrolment. This not solely inflates prices and delays outcomes, but in addition undermines the reliability of latest therapies.

At the moment, screening sufferers for trials is a guide course of. Researchers should evaluate every affected person’s medical information to find out in the event that they meet eligibility standards, which takes round 40 minutes per affected person. With restricted workers and sources, this course of is usually too sluggish to maintain up with demand.

A part of the issue is that precious affected person data contained in digital well being information (EHRs) is usually buried in unstructured textual content, similar to medical doctors’ notes, which conventional machine studying software program struggles to decipher. Consequently, many eligible sufferers are neglected as a result of there merely isn’t sufficient capability to evaluate each case. This contributes to low enrolment charges, trial delays and even cancellations, finally slowing down entry to new therapies.

To counter this downside, the researchers have checked out methods of rushing up the screening course of by utilizing ChatGPT. Researchers used GPT-3.5 and GPT-4 to analyse 74 sufferers’ information to see in the event that they certified for a head and neck most cancers trial.

3 ways of prompting the AI have been examined:

  • Structured Output (SO): asking for solutions in a set format.
  • Chain of Thought (CoT): asking the mannequin to elucidate its reasoning.
  • Self-Uncover (SD): letting the mannequin work out what to search for.

The outcomes have been promising. GPT-4 was extra correct than GPT-3.5, although barely slower and costlier. Screening occasions ranged from 1.4 to 12.4 minutes per affected person, with prices between $0.02 and $0.27.

LLMs like GPT-4 may help display sufferers for medical trials, particularly when utilizing versatile standards. They’re not good, particularly when all guidelines should be met, however they’ll save time and help human reviewers.”

Dr. Mike Dohopolski, lead writer of the examine

This analysis highlights the potential for AI to help quicker, extra environment friendly medical trials – bringing new therapies to sufferers sooner.

The examine is without doubt one of the first articles printed in IOP Publishing’s Machine Studying collection™, the world’s first open entry journal collection devoted to the appliance and growth of machine studying (ML) and synthetic intelligence (AI) for the sciences.

The identical analysis workforce have labored on a technique that permits surgeons to regulate sufferers’ radiation remedy in actual time while they’re nonetheless on the desk. Utilizing a deep studying system known as GeoDL, the AI delivers exact 3D dose estimates from CT scans and therapy information in simply 35 milliseconds. This might make adaptive radiotherapy quicker and extra environment friendly in actual medical settings.

Supply:

Journal reference:

Beattie, J., et al. (2025). ChatGPT augmented medical trial screening. Machine Studying: Well beingdoi.org/10.1088/3049-477x/adbd47.

ios – xcode run kotlin multiplatform mission can’t set up iosApp on IPhone16


Xcode run kotlin multiplatform mission to put in iosApp on IPhone16, tips on how to mounted it ?

I had obtain a clean kmp mission , and put in efficiently on IPhone16. After putting in the iOS app on an actual machine (iPhone 15), it was instantly uninstalled. Xcode reported the error proven within the screenshot.

and it may be archived to AppStore.

enter image description here

无法安装“KotlinAppProject”
Area: IXUserPresentableErrorDomain
Code: 1
Restoration Suggestion: Software is lacking the application-identifier entitlement.
Person Data: {
    DVTErrorCreationDateKey = "2025-08-03 11:32:01 +0000";
    IDERunOperationFailingWorker = IDEInstallCoreDeviceWorker;
}
--
Failed to put in the app on the machine.
Area: com.apple.dt.CoreDeviceError
Code: 3002
Person Data: {
    NSURL = "file:///Customers/HOX4SGH/Library/Developer/Xcode/DerivedData/iosApp-gbaojemzkfyvhrbgladtchqcvlfq/Construct/Merchandise/Debug-iphoneos/KotlinAppProject.app";
}
--
无法安装“KotlinAppProject”
Area: IXUserPresentableErrorDomain
Code: 1
Failure Cause: 请稍后再试。
Restoration Suggestion: Software is lacking the application-identifier entitlement.
--
Software is lacking the application-identifier entitlement.
Area: MIInstallerErrorDomain
Code: 63
Person Data: {
    FunctionName = "-[MIInstallableBundle _validateApplicationIdentifierForNewBundleSigningInfo:error:]";
    LegacyErrorString = ApplicationVerificationFailed;
    SourceFileLine = 1130;
}
--

Occasion Metadata: com.apple.dt.IDERunOperationWorkerFinished : {
    "device_identifier" = "00008140-000435313CF2801C";
    "device_isCoreDevice" = 1;
    "device_model" = "iPhone17,3";
    "device_osBuild" = "18.5 (22F76)";
    "device_platform" = "com.apple.platform.iphoneos";
    "device_thinningType" = "iPhone17,3";
    "dvt_coredevice_version" = "443.24";
    "dvt_coresimulator_version" = "1010.15";
    "dvt_mobiledevice_version" = "1784.120.3";
    "launchSession_schemeCommand" = Run;
    "launchSession_state" = 1;
    "launchSession_targetArch" = arm64;
    "operation_duration_ms" = 5069;
    "operation_errorCode" = 1;
    "operation_errorDomain" = IXUserPresentableErrorDomain;
    "operation_errorWorker" = IDEInstallCoreDeviceWorker;
    "operation_name" = IDERunOperationWorkerGroup;
    "param_debugger_attachToExtensions" = 0;
    "param_debugger_attachToXPC" = 1;
    "param_debugger_type" = 3;
    "param_destination_isProxy" = 0;
    "param_destination_platform" = "com.apple.platform.iphoneos";
    "param_diag_113575882_enable" = 0;
    "param_diag_MainThreadChecker_stopOnIssue" = 0;
    "param_diag_MallocStackLogging_enableDuringAttach" = 0;
    "param_diag_MallocStackLogging_enableForXPC" = 1;
    "param_diag_allowLocationSimulation" = 1;
    "param_diag_checker_tpc_enable" = 1;
    "param_diag_gpu_frameCapture_enable" = 0;
    "param_diag_gpu_shaderValidation_enable" = 0;
    "param_diag_gpu_validation_enable" = 0;
    "param_diag_guardMalloc_enable" = 0;
    "param_diag_memoryGraphOnResourceException" = 0;
    "param_diag_mtc_enable" = 1;
    "param_diag_queueDebugging_enable" = 1;
    "param_diag_runtimeProfile_generate" = 0;
    "param_diag_sanitizer_asan_enable" = 0;
    "param_diag_sanitizer_tsan_enable" = 0;
    "param_diag_sanitizer_tsan_stopOnIssue" = 0;
    "param_diag_sanitizer_ubsan_enable" = 0;
    "param_diag_sanitizer_ubsan_stopOnIssue" = 0;
    "param_diag_showNonLocalizedStrings" = 0;
    "param_diag_viewDebugging_enabled" = 1;
    "param_diag_viewDebugging_insertDylibOnLaunch" = 1;
    "param_install_style" = 2;
    "param_launcher_UID" = 2;
    "param_launcher_allowDeviceSensorReplayData" = 0;
    "param_launcher_kind" = 0;
    "param_launcher_style" = 99;
    "param_launcher_substyle" = 0;
    "param_runnable_appExtensionHostRunMode" = 0;
    "param_runnable_productType" = "com.apple.product-type.software";
    "param_structuredConsoleMode" = 1;
    "param_testing_launchedForTesting" = 0;
    "param_testing_suppressSimulatorApp" = 0;
    "param_testing_usingCLI" = 0;
    "sdk_canonicalName" = "iphoneos18.5";
    "sdk_osVersion" = "18.5";
    "sdk_variant" = iphoneos;
}
--


System Data

macOS Model 15.5 (Construct 24F74)
Xcode 16.4 (23792) (Construct 16F6)
Timestamp: 2025-08-03T19:32:01+08:00

Flutter iOS app UI proven on startup earlier than splash


I’m constructing an app for ios/android utilizing flutter. When the app begins, the move is:

important.dart
native splash displaying dev emblem (throughout which app begin up occurs)
authgate
app widget (extracted this from important to cut back how a lot work important was doing)
flutter splash displaying app emblem (throughout which permissions are referred to as)
touchdown display screen

The problem I’m seeing is when the iOS app begins, it briefly flashes the final seen UI display screen BEFORE the native splash display screen. e.g. If I used to be viewing the settings display screen within the app then stop the app, subsequent time I begin the app, the very first thing I see earlier than the native splash display screen is a flash of the settings display screen.

I simply wished to know if anybody has skilled that earlier than, and the way they resolved it.

I’ve googled for hours and can’t discover something related, nor can I discover something in flutter documentation. It appears I’ve managed to do one thing in begin up that created this challenge that nobody else will get? It’s driving me insane. On condition that this happens previous to native splash, I assume it’s a snapshot specific to iOS because it doesn’t occur within the android app, and whereas it’s not a breaking challenge, it doesn’t look nice from a consumer perspective.

I’ve tried including a white background to cover snapshot, as an alternative I received native splash then white display screen then native splash once more so eliminated the white background.
Added UIApplication.shared.ignoreSnapshotOnNextApplicationLaunch() to AppDelegate with no change in behaviour

1. Most important.dart

Future important() async {
  WidgetsFlutterBinding.ensureInitialized();
  tz.initializeTimeZones();
  await Future.delayed(const Period(seconds: 2));

  await Firebase.initializeApp(choices: DefaultFirebaseOptions.currentPlatform);
  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);

  await Hive.initFlutter();
  Hive.registerAdapter(MedicationAdapter());  // TypeID 0
  Hive.registerAdapter(DoseEntryAdapter()); // TypeID 1
  Hive.registerAdapter(HealthProfessionalAdapter()); // TypeID 2
  Hive.registerAdapter(DiscussionItemAdapter()); // TypeID 3
  Hive.registerAdapter(AppointmentAdapter()); // TypeID 4
  Hive.registerAdapter(UserProfileAdapter()); // TypeID 5
  Hive.registerAdapter(TodoItemAdapter()); // TypeID 7
  Hive.registerAdapter(DiaryEntryAdapter()); // TypeID 8
  Hive.registerAdapter(SelectedTrackersAdapter()); // TypeID 11
  Hive.registerAdapter(SelectedGoalsAdapter()); // TypeID 70
  Hive.registerAdapter(GpsActivityEntryAdapter()); // TypeID 60
  Hive.registerAdapter(WeightEntryAdapter()); // TypeID 50
  Hive.registerAdapter(WeightGoalAdapter()); // TypeID 31
  Hive.registerAdapter(ActivityGoalAdapter()); // TypeID 28
  Hive.registerAdapter(DailyGoalProgressAdapter()); // TypeID 33
  Hive.registerAdapter(WeeklyWeightEntryAdapter()); // TypeID 32
  Hive.registerAdapter(MenstrualCycleEntryAdapter()); // TypeID 43
  Hive.registerAdapter(WorkoutActivityAdapter()); // TypeID 41
  Hive.registerAdapter(MeditationGoalAdapter()); // TypeID 98
  Hive.registerAdapter(DailyMeditationProgressAdapter()); // TypeID 97

  await Hive.openBox('settings');
  await Hive.openBox('medicationAlertsSent');
  await Hive.openBox('menstrualCycleBox');
  await Hive.openBox('gps_activities');
  await Hive.openBox('gpsActivity');

  await NotificationService.initialize();
  await LocalisationSettingsService.init();

  // Load saved locale
  last savedLocaleCode = LocalisationSettingsService.getSelectedLocale();
  last initialLocale = savedLocaleCode != null ? Locale(savedLocaleCode) : null;

  runApp(
    MultiProvider(
      suppliers: [
        ChangeNotifierProvider(create: (_) => ThemeNotifier()),
        ChangeNotifierProvider(create: (_) => LocaleNotifier()..setLocale(initialLocale)),
      ],
      youngster: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({tremendous.key});

  @override
  Widget construct(BuildContext context) {
    last themeNotifier = Supplier.of(context);
    last localeNotifier = Supplier.of(context);

    return MaterialApp(
        title: 'Pebbl',
        navigatorKey: navigatorKey,
        theme: AppTheme.lightTheme,
        darkTheme: AppTheme.darkTheme,
        themeMode: themeNotifier.themeMode,
        debugShowCheckedModeBanner: false,
        residence: const NativeSplashWrapper(),
        locale: localeNotifier.locale,
        localizationsDelegates: const [
          AppLocalizations.delegate,
          GlobalMaterialLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
        ],
        supportedLocales: AppLocalizations.supportedLocales,
        localeResolutionCallback: (locale, supportedLocales) {
          for (var supportedLocale in supportedLocales) {
            if (supportedLocale.languageCode == locale?.languageCode &&
                supportedLocale.countryCode == locale?.countryCode) {
              return supportedLocale;
            }
          }
          return const Locale('en', 'GB');
        }
    );
  }
}

2.  Native splash wrapper

import 'package deal:flutter/materials.dart';
import 'package deal:pebbl/screens/login/auth_gate.dart'; // ✅ Now this works

class NativeSplashWrapper extends StatefulWidget {
  const NativeSplashWrapper({tremendous.key});

  @override
  State createState() => _NativeSplashWrapperState();
}

class _NativeSplashWrapperState extends State {
  bool _ready = false;

  @override
  void initState() {
    tremendous.initState();
    _init();
  }

  Future _init() async {
    await Future.delayed(const Period(milliseconds: 100));
    if (mounted) {
      setState(() {
        _ready = true;
      });
    }
  }

  @override
  Widget construct(BuildContext context) {
    if (!_ready) {
      return const Scaffold(
        backgroundColor: Coloration(0xFFF5F5F5),
        physique: Middle(
          youngster: Picture(
            picture: AssetImage('belongings/photographs/pebbl_logo.png'),
            width: 200,
            top: 200,
          ),
        ),
      );
    }
    return const AuthGate();
  }
}
3. Pubspec.yaml (snippet for flutter native splash)

flutter_native_splash:
  colour: "#F5F5F5"
  picture: belongings/photographs/dev_logo.png
  fullscreen: true
  android: true
  ios: true

  android_12:
    picture: belongings/photographs/android12_dev_logo.png
4. Auth gate

import 'package deal:flutter/materials.dart';
import 'package deal:firebase_auth/firebase_auth.dart';
import 'package deal:pebbl/screens/login/splash_screen.dart';
import 'package deal:pebbl/screens/login/login_screen.dart';
import 'package deal:pebbl/widgets/pebbl_app.dart'; // We’ll extract PebblApp too (see beneath)

class AuthGate extends StatelessWidget {
  const AuthGate({tremendous.key});

  @override
  Widget construct(BuildContext context) {
    return StreamBuilder(
      stream: FirebaseAuth.occasion.authStateChanges(),
      builder: (context, authSnapshot) {
        last isLoggedIn = authSnapshot.hasData;
        last display screen = isLoggedIn ? SplashScreen() : const LoginScreen();
        return PebblApp(initialScreen: display screen);
      },
    );
  }
}
5. Pebbl app widget

import 'package deal:flutter/materials.dart';
import 'package deal:pebbl/screens/touchdown/landing_screen.dart';
import 'package deal:pebbl/companies/notification_service.dart';
import 'package deal:pebbl/utils/logger.dart';
import 'package deal:pebbl/important.dart'; // for navigatorKey

class PebblApp extends StatefulWidget {
  last Widget initialScreen;

  const PebblApp({tremendous.key, required this.initialScreen});

  @override
  State createState() => _PebblAppState();
}

class _PebblAppState extends State with WidgetsBindingObserver {
  @override
  void initState() {
    tremendous.initState();
    WidgetsBinding.occasion.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.occasion.removeObserver(this);
    tremendous.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      last payload = NotificationService.getAndClearPendingPayload();
      if (payload != null) {
        Logger.log('App resumed. Routing to payload: $payload');
        navigatorKey.currentState?.pushAndRemoveUntil(
          MaterialPageRoute(builder: (_) => LandingScreen(payload: payload)),
              (route) => false,
        );
      }
    }
  }

  @override
  Widget construct(BuildContext context) {
    return GestureDetector(
      onTap: () => FocusScope.of(context).unfocus(),
      youngster: widget.initialScreen,
    );
  }
}
6. Splash display screen

import 'package deal:flutter/basis.dart';
import 'package deal:pebbl/utils/logger.dart';
import 'dart:io';
import 'package deal:device_info_plus/device_info_plus.dart';
import 'package deal:flutter/materials.dart';
import 'package deal:firebase_auth/firebase_auth.dart';
import 'package deal:package_info_plus/package_info_plus.dart';
import 'package deal:pebbl/screens/touchdown/landing_screen.dart';
import 'package deal:pebbl/screens/login/login_screen.dart';
import 'package deal:permission_handler/permission_handler.dart';
import 'package deal:pebbl/companies/notification_service.dart';
import 'package deal:geolocator/geolocator.dart';

class SplashScreen extends StatefulWidget {
  last String? payloadOverride;

  const SplashScreen({tremendous.key, this.payloadOverride});

  @override
  State createState() => _SplashScreenState();
}

class _SplashScreenState extends State with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation _animation;
  String _version = '';

  @override
  void initState() {
    tremendous.initState();
    _controller = AnimationController(
      period: const Period(seconds: 2),
      vsync: this,
    )..ahead();

    _animation = CurvedAnimation(
      mother or father: _controller,
      curve: Curves.easeInOut,
    );

    _init();
  }

  Future _init() async {
    strive {
      last data = await PackageInfo.fromPlatform();
      setState(() {
        _version = 'v${data.model}+${data.buildNumber}';
      });
      if (kDebugMode) {
        Logger.log('✅ Bundle data loaded');
      }
    } catch (e) {
      if (kDebugMode) {
        Logger.log('❌ Bundle data failed: $e');
      }
      _version = 'v1.0.0';
    }

    // 🔒 iOS location permission verify
    strive {
      if (Platform.isIOS) {
        last serviceEnabled = await Geolocator.isLocationServiceEnabled();
        if (kDebugMode) {
          Logger.log('✅ [iOS] Location service enabled: $serviceEnabled');
        }
        if (serviceEnabled) {
          var permission = await Geolocator.checkPermission();
          if (kDebugMode) {
            Logger.log('✅ [iOS] Location permission standing: $permission');
          }
          if (permission == LocationPermission.denied) {
            permission = await Geolocator.requestPermission();
            if (kDebugMode) {
              Logger.log('✅ [iOS] Location permission requested: $permission');
            }
          }
        }
      }
    } catch (e) {
      if (kDebugMode) {
        Logger.log('iOS Location permission request failed: $e');
      }
    }

    // ✅ Android 13+ notification permission
    strive {
      if (Platform.isAndroid) {
        last androidInfo = await DeviceInfoPlugin().androidInfo;
        if (kDebugMode) {
          Logger.log('✅ Android SDK: ${androidInfo.model.sdkInt}');
        }
        if (androidInfo.model.sdkInt >= 33) {
          last standing = await Permission.notification.request();
          if (kDebugMode) {
            Logger.log('✅ Notification permission: $standing');
          }
          if (!standing.isGranted) {
            if (kDebugMode) {
              Logger.log('Notification permission denied');
            }
            // Optionally present a dialog right here
          }
        }
      }
    } catch (e) {
      if (kDebugMode) {
        Logger.log('Notification permission request failed: $e');
      }
    }

    // ✅ Android location permissions: foreground and background
    strive {
      if (Platform.isAndroid) {
        // ✅ 1. Test and request notification permission (Android 13+)
        last notifStatus = await Permission.notification.standing;
        if (!notifStatus.isGranted) {
          if (kDebugMode) {
            Logger.log('🔔 Requesting notification permission...');
          }
          last notifResult = await Permission.notification.request();
          if (kDebugMode) {
            Logger.log('🔔 Notification permission outcome: $notifResult');
          }
        }

        // ✅ 2. Test foreground location permission
        if (kDebugMode) {
          Logger.log('📍 Checking foreground location permission...');
        }
        var fgStatus = await Permission.location.standing;
        if (kDebugMode) {
          Logger.log('📍 Foreground location permission standing: $fgStatus');
        }

        if (!fgStatus.isGranted) {
          if (kDebugMode) {
            Logger.log('📍 Requesting foreground location permission...');
          }
          fgStatus = await Permission.location.request();
          if (kDebugMode) {
            Logger.log('📍 Foreground location permission outcome: $fgStatus');
          }
        }

        // ✅ 3. Test background location permission (if foreground granted)
        if (fgStatus.isGranted) {
          if (kDebugMode) {
            Logger.log('📍 Checking background location permission...');
          }
          var bgStatus = await Permission.locationAlways.standing;
          if (kDebugMode) {
            Logger.log('📍 Background location permission standing: $bgStatus');
          }

          if (!bgStatus.isGranted) {
            if (kDebugMode) {
              Logger.log('📍 Requesting background location permission...');
            }
            bgStatus = await Permission.locationAlways.request();
            if (kDebugMode) {
              Logger.log('📍 Background location permission outcome: $bgStatus');
            }
          } else {
            if (kDebugMode) {
              Logger.log('✅ Background location permission already granted');
            }
          }
        } else {
          if (kDebugMode) {
            Logger.log('❌ Foreground location denied, skipping background request');
          }
        }
      }
    } catch (e) {
      if (kDebugMode) {
        Logger.log('❗ Permission request failed: $e');
      }
    }


    await Future.delayed(const Period(seconds: 2));
    if (!mounted) return;

    last consumer = FirebaseAuth.occasion.currentUser;
    if (kDebugMode) {
      Logger.log('SplashScreen: currentUser = ${consumer?.uid}');
    }
    last payload = widget.payloadOverride ??
        NotificationService.getInitialPayload() ??
        NotificationService.consumePendingPayload();
    if (kDebugMode) {
      Logger.log('SplashScreen init: Firebase consumer: ${consumer?.uid}, payload: $payload');
    }
    if (kDebugMode) {
      Logger.log('SplashScreen: payload resolved = $payload');
    }

    if (consumer != null) {
      strive {
        if (kDebugMode) {
          Logger.log('Calling rescheduleAllReminders...');
        }
        await NotificationService.rescheduleAllReminders()
            .timeout(const Period(seconds: 5));
        if (kDebugMode) {
          Logger.log('rescheduleAllReminders accomplished');
        }
      } catch (e) {
        if (kDebugMode) {
          Logger.log('rescheduleAllReminders failed or timed out: $e');
        }
      }
    }

    if (!mounted) return;

    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) => consumer == null
            ? const LoginScreen()
            : LandingScreen(payload: payload),
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    tremendous.dispose();
  }

  @override
  Widget construct(BuildContext context) {
    return Scaffold(
      backgroundColor: const Coloration(0xFFF5F5F5),
      physique: Column(
        mainAxisAlignment: MainAxisAlignment.heart,
        youngsters: [
          const Spacer(),
          FadeTransition(
            opacity: _animation,
            child: Center(
              child: Image.asset(
                'assets/images/pebbl_logo.png',
                width: 200,
                height: 200,
              ),
            ),
          ),
          const Spacer(),
          Padding(
            padding: const EdgeInsets.only(bottom: 20),
            child: Text(
              _version,
              style: const TextStyle(color: Colors.black54),
            ),
          ),
        ],
      ),
    );
  }
}
AppDelegate

import UIKit
import Flutter
import UserNotifications
import AVFAudio
import GoogleMaps // 👈 Add this import for Maps

@important
@objc class AppDelegate: FlutterAppDelegate {
  //lazy var flutterEngine = FlutterEngine(identify: "my_engine")
  override func software(
    _ software: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {

    UIApplication.shared.ignoreSnapshotOnNextApplicationLaunch()

// Begin engine (plugins auto-register when the engine is hooked up to the view)
    //flutterEngine.run()
    // Arrange audio playback class
    do {
      strive AVAudioSession.sharedInstance().setCategory(
        .playback,
        mode: .default,
        choices: [.mixWithOthers]
      )
      strive AVAudioSession.sharedInstance().setActive(true)
    } catch {
      print("Didn't set audio session class.")
    }

    // ✅ Register Google Maps API key
    GMSServices.provideAPIKey("key") // 👈 Change along with your precise key

    // Guarantee notification faucets are delivered to Flutter
    UNUserNotificationCenter.present().delegate = self

    return tremendous.software(software, didFinishLaunchingWithOptions: launchOptions)

  func applicationWillResignActive(_ software: UIApplication) {
      // Add a white view over the window earlier than backgrounding
      let whiteView = UIView(body: window?.bounds ?? .zero)
      whiteView.backgroundColor = UIColor.white
      whiteView.tag = 999 // So we are able to take away it later
      window?.addSubview(whiteView)
  }

  func applicationDidBecomeActive(_ software: UIApplication) {
      // Take away the white view when app turns into energetic
      if let whiteView = window?.viewWithTag(999) {
          whiteView.removeFromSuperview()
      }
  }
  }
}
SceneDelegate

import UIKit
import Flutter

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?

  func scene(_ scene: UIScene,
             willConnectTo session: UISceneSession,
             choices connectionOptions: UIScene.ConnectionOptions) {

    guard let windowScene = (scene as? UIWindowScene) else { return }

    let window = UIWindow(windowScene: windowScene)

    //let appDelegate = UIApplication.shared.delegate as! AppDelegate
    //let flutterEngine = appDelegate.flutterEngine

    let flutterViewController = FlutterViewController()

    GeneratedPluginRegistrant.register(with: flutterViewController.engine)

    window.rootViewController = flutterViewController
    self.window = window
    window.makeKeyAndVisible()
  }
}

ios – Learn how to repair the gestureRecognizer over PDFKit breaking the paging within the new ios26 model?


I had mission going nice, the place i wanted to do stuff with pdfs, drawing on prime them and so on. Since apple is all closed sourced i wanted to turn out to be a bit hacky. In any case, i’ve an issue because the new ios 26 replace which breaks the behaviour. I simplified the code very a lot right into a demo mission, the place you possibly can rapidly see what’s mistaken.

When swiping left to go to the subsequent web page, it does change the web page and so on within the pdf Doc, however visually nothing occurs. I’m caught on the primary web page. I dont know what to do, tried plenty of issues, however nothing works. Anybody expert sufficient to assist me out?

import UIKit
import PDFKit
import SwiftUI

class PDFViewController: UIViewController {
    
    var pdfView: PDFView!
    var gestureHandler: GestureHandler!

    override func viewDidLoad() {
        tremendous.viewDidLoad()
        setupPDFView()
        setupGestureHandler()
        loadPDF()
    }
    
    personal func setupPDFView() {
        pdfView = PDFView(body: view.bounds)
        
        // Your actual configuration
        pdfView.autoScales = true
        pdfView.pageShadowsEnabled = false
        pdfView.backgroundColor = .white
        pdfView.displayMode = .singlePage
        
        view.addSubview(pdfView)
        
        // Setup constraints
        pdfView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            pdfView.topAnchor.constraint(equalTo: view.topAnchor),
            pdfView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            pdfView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            pdfView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
  
  personal func setupGestureHandler() {
          gestureHandler = GestureHandler(pdfView: pdfView)
          gestureHandler.setupSwipeGestures(on: view)
      }
    
    personal func loadPDF() {
        if let path = Bundle.principal.path(forResource: "sonate12", ofType: "pdf"),
           let doc = PDFDocument(url: URL(fileURLWithPath: path)) {
            pdfView.doc = doc
        } else {
            print("Couldn't discover sonate12.pdf in bundle")
        }
    }
}


class GestureHandler {
    
    personal weak var pdfView: PDFView?
    
    init(pdfView: PDFView) {
        self.pdfView = pdfView
    }
    
    func setupSwipeGestures(on view: UIView) {
        // Left swipe - go to subsequent web page
        let leftSwipe = UISwipeGestureRecognizer(goal: self, motion: #selector(handleSwipe(_:)))
        leftSwipe.route = .left
        view.addGestureRecognizer(leftSwipe)
        
        // Proper swipe - go to earlier web page
        let rightSwipe = UISwipeGestureRecognizer(goal: self, motion: #selector(handleSwipe(_:)))
        rightSwipe.route = .proper
        view.addGestureRecognizer(rightSwipe)
    }
    
    @objc personal func handleSwipe(_ gesture: UISwipeGestureRecognizer) {
        guard let pdfView = pdfView,
              let doc = pdfView.doc,
              let currentPage = pdfView.currentPage else {
            print("🚫 No PDF view, doc, or present web page out there")
            return
        }
        
        let currentIndex = doc.index(for: currentPage)
        let totalPages = doc.pageCount
        
        print("📄 Present state: Web page (currentIndex + 1) of (totalPages)")
        print("👆 Swipe route: (gesture.route == .left ? "LEFT (subsequent)" : "RIGHT (earlier)")")
        
        swap gesture.route {
        case .left:
            // Subsequent web page
            guard currentIndex < doc.pageCount - 1 else {
                print("🚫 Already on final web page ((currentIndex + 1)), can not go ahead")
                return
            }
            
            let nextPage = doc.web page(at: currentIndex + 1)
            if let web page = nextPage {
                print("➡️ Going to web page (currentIndex + 2)")
                pdfView.go(to: web page)
              pdfView.setNeedsDisplay()
              pdfView.layoutIfNeeded()
                // Test if navigation truly labored
                DispatchQueue.principal.asyncAfter(deadline: .now() + 0.1) {
                    if let newCurrentPage = pdfView.currentPage {
                        let newIndex = doc.index(for: newCurrentPage)
                        print("✅ Navigation consequence: Now on web page (newIndex + 1)")
                        if newIndex == currentIndex {
                            print("⚠️ WARNING: Web page did not change visually!")
                        }
                    }
                }
            } else {
                print("🚫 Couldn't get subsequent web page object")
            }
            
        case .proper:
            // Earlier web page
            guard currentIndex > 0 else {
                print("🚫 Already on first web page (1), can not return")
                return
            }
            
            let previousPage = doc.web page(at: currentIndex - 1)
            if let web page = previousPage {
                print("⬅️ Going to web page (currentIndex)")
                pdfView.go(to: web page)
              pdfView.setNeedsDisplay()
              pdfView.layoutIfNeeded()
              let bounds = pdfView.bounds
              pdfView.bounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.width + 0.01, peak: bounds.peak)
              pdfView.bounds = bounds

                
                // Test if navigation truly labored
                DispatchQueue.principal.asyncAfter(deadline: .now() + 0.1) {
                    if let newCurrentPage = pdfView.currentPage {
                        let newIndex = doc.index(for: newCurrentPage)
                        print("✅ Navigation consequence: Now on web page (newIndex + 1)")
                        if newIndex == currentIndex {
                            print("⚠️ WARNING: Web page did not change visually!")
                        }
                    }
                }
            } else {
                print("🚫 Couldn't get earlier web page object")
            }
            
        default:
            print("🤷‍♂️ Unknown swipe route")
            break
        }
    }
}


struct PDFViewerRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> PDFViewController {
        return PDFViewController()
    }
    
    func updateUIViewController(_ uiViewController: PDFViewController, context: Context) {
        // No updates wanted
    }
}

You may take a look at the code right here as effectively: https://github.com/vallezw/swift-bug-ios26

goal c – iOS Dylib crashes when printed to testflight with CODESIGNING 2 Invalid Web page


It is a prolonged one. I’ve mainly compiled a Rust binary right into a dylib and packaged right into a .xcframework that incorporates per arch .frameworks. This hundreds accurately when run from Xcode into an actual iOS gadget. Nonetheless, when deployed to TestFlight the app crashes.

Here’s what is a bit completely different, the dylib just isn’t absolutely self-contained. It tries to succeed in in an use C features I’ve uncovered in my library code. Calling features which can be simply inside the dylib and simply return works tremendous, however the second it tries to name one of many uncovered features it crashes.

A full in-depth step-by-step of how I packaged the binaries might be present in my web site:

https://ospfranco.com/complete-guide-to-dylibs-in-ios-and-android

After I have a look at the TestFlight crash report there aren’t any symbols however the termination trigger by way of WatchDog is:

Termination Purpose: CODESIGNING 2 Invalid Web page

I’ve declared my features as such:

OBJC_EXTERN void ios_prepare_request(const char *url)
#outline EXPORT __attribute__((visibility("default"), used, retain))
 
extern "C" {
 
EXPORT void ios_prepare_request(const char *url) {
  NSString *urlString = [NSString stringWithUTF8String:url];
  request =
      [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
}
 
}
 
// Perform used to stop optimization
void force_symbol_registration() {
  // Pressure these symbols to be included within the binary by referencing them
  risky void *ptrs[] = {(void *)ios_prepare_request,};
 
  // Stop compiler from optimizing away the array
  (void)ptrs;
}

And I load my framework as:

  opacity::force_symbol_registration();
 
  // NSBundle *dylib_bundle =
  //     [NSBundle bundleWithIdentifier:@"com.opacitylabs.sdk"];
  // NSString *dylib_path = [dylib_bundle pathForResource:@"sdk" ofType:@""];
 
  // // Load the dynamic library
  // void *deal with = dlopen([dylib_path UTF8String], RTLD_NOW | RTLD_GLOBAL);
  // if (!deal with) {
  //   NSString *errorMessage = [NSString stringWithUTF8String:dlerror()];
  //   *error =
  //       [NSError errorWithDomain:@"OpacitySDKDylibError"
  //                           code:1002
  //                       userInfo:@{NSLocalizedDescriptionKey :
  //                       errorMessage}];
  //   return -1; // or applicable error code
  // }
 
  // Be sure that the principle executable's symbols can be found
  dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
 
  NSBundle *frameworkBundle =
      [NSBundle bundleWithIdentifier:@"com.opacitylabs.sdk"];
  if (![frameworkBundle isLoaded]) {
    BOOL success = [frameworkBundle load];
    if (!success) {
      NSString *errorMessage = @"Did not load framework";
      *error =
          [NSError errorWithDomain:@"OpacitySDKDylibError"
                              code:1002
                          userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
      return -1;
    }
  }
  • As you may see, I’ve additionally tried dlopen each work when run from Xcode however crash when deployed on testflight.
  • I’ve tried re-signing the xcframework/frameworks on a pre construct step but it surely would not work
  • As acknowledged, I can name the features contained in the dylib, however as soon as they attempt to name my uncovered code it crashes

Is that this achievable in any respect or only a limitation of the iOS sandbox?