Jump to content

alejandro.sawers

Members
  • Content Count

    35
  • Joined

  • Last visited

Everything posted by alejandro.sawers

  1. alejandro.sawers

    iOS Selectors in Delphi

    iOS has a convenient way to save images to the user's device without requiring full access to the photo library, and luckily the required call is included in the iOSapi.UIKit unit in Delphi. So just doing something like this: UIImageWriteToSavedPhotosAlbum(NSObjectToID(Image), nil, nil, nil); // Image is a TUIImage instance And the system will take care of asking the corresponding user authorization and saving the image. Now if something goes wrong (from the user denying authorization to some failure on the save process) the app can get error info by filling the 2nd and 3rd parameter when calling the procedure. These parameters are quite special however: a Selector and its Target. According to the documentation I understand that a Selector allows to call an arbitrary procedure of a NSObject regardless of its class. Given a FMX TForm with a procedure CompletionHandler to act as the completion receiver: - Can a FMX TForm be casted to a NSObject to be used as completonTarget? - Is the procedure signature CompletionHandler(image: UIImage; error: NSError; contextInfo: Pointer) correct and suitable? - It's enough something like NSSelectorFromString(NSObjectToID(StrToNSStr('CompletionHandler'))) to make a Selector for a Delphi method name? - Will be possible to pass a valid Selector on Delphi at all?
  2. alejandro.sawers

    iOS Selectors in Delphi

    I might do that, explaining the best I can what happened here. And about the demo, yes it is really good but overkill for my use case, but now I know the imports I need are in the Kastri repo, on the DW.iOSapi.Photos unit, so I can use just the bits related to permission checking and requesting. But... - PHPhotoLibrary.requestAuthorization asks for full-access, so aware users will see the inconsistency between the request and the purpose (save a single image) and will deny. I can always ask them again to give the previously denied permission explaining what's happening, but still feels hacky. Someone at Apple forgot a couple things about consistency when designed this. - On iOS 14+ we finally have ways to request and check write-only access to the photo library via authorizationStatusForAccessLevel and requestAuthorizationForAccessLevel. These are missing from Kastri but are trivial to import, except for requestAuthorizationForAccessLevel which asks for a "void (^)(PHAuthorizationStatus status)" parameter as the handler. That thing looks scary.
  3. alejandro.sawers

    iOS Selectors in Delphi

    Well, after reading dozens of Objective-C documentation pages, diving into the internals of the Macapi.* and iOSapi.* units, and looking for clues and hints from several (and quite old) iOS-and-Delphi blog entries I finally have a working implementation of an iOS Selector in Delphi, tailored for usage with UIImageWriteToSavedPhotosAlbum (in Delphi 12.2 unpatched): Note: I'm really no expert on iOS internals, so if mistakes were made (whether technical of terminological) feel free to correct me. - First, we need a Delphi class that is also an Objective-C class. I based my implementation on the TFMXWakeHandler class in FMX.Platform.iOS, as it is simple enough to understand and replicate: uses Macapi.ObjectiveC, iOSapi.Foundation, iOSapi.UIKit, System.TypInfo; type ICompletionTarget = interface(NSObject) ['your-guid-goes-here'] // Use Ctrl+Shift+G to get a random GUID [MethodName('image:didFinishSavingWithError:contextInfo:')] procedure saveImageCompletionHandler(image: UIImage; error: NSError; contextInfo: Pointer); cdecl; end; TCompletionTarget = class(TOCLocal) private function GetNativeObject: NSObject; // From TFMXWakeHandler protected function GetObjectiveCClass: PTypeInfo; override; // From TFMXWakeHandler public [MethodName('image:didFinishSavingWithError:contextInfo:')] procedure saveImageCompletionHandler(image: UIImage; error: NSError; contextInfo: Pointer); cdecl; property NativeObject: NSObject read GetNativeObject; // From TFMXWakeHandler end; With this, TCompletionTarget will also create an Objc object when the Delphi object itself is created, as Delphi takes care of registering the class and its methods on the Objc side. I added the [MethodName] attribute to saveImageCompletionHandler so the Delphi procedure and it's arguments can be arbitrarily named while keeping the selector name static and compliant with the signature required by UIImageWriteToSavedPhotosAlbum. It's important however to match the argument types to those expected by the selector as close as possible. The mapping between iOS types and Delphi types is in charge of the RTTI and it does a good job, except for the contextInfo parameter: If you examine the procedure MangleType(var Buff: string; const RttiType: TRttiType) on the unit Macapi.ObjectiveC you will see that the tkPointer type is mapped to the character '^', but the correct mapping for a 'void *' (a pointer to a void) is '^v'. So... - Patch Macapi.ObjectiveC.pas to force a custom encoding for our signature: MethodName := MangleMethodName(ClassMethod); MangledName := MangleMethodType(ClassMethod); // Mangled name for our selector is v@:@@^ , which will not be accepted by the callback and will throw an exception if MethodName='image:didFinishSavingWithError:contextInfo:' then // Given our selector is unique we can force a custom MangledName on it MangledName := 'v@:@@^v'; // void, id, SEL, UIImage, NSError, void * My solution was to edit Macapi.ObjectiveC.pas, on the class function TRegisteredDelphiClass.RegisterClass, intercept my custom selector and force a custom encoded representation. With this, the method signature and the encoded representation will be accepted by the callback invoked by UIImageWriteToSavedPhotosAlbum. This was the hardest part to figure out, as a crash on iOS closes the app without further info and the XCode logs are barely helpful at best. - Create an instance of TCompletionTarget, pass it to UIImageWriteToSavedPhotosAlbum and handle the result: // Initialize it in e.g. FormCreate Obj := TCompletionTarget.Create(SaveImageCompletionHandler); // Save the photo and pass the target and selector UIImageWriteToSavedPhotosAlbum( NSObjectToID(Image), // UIImage NSObjectToID(Obj.NativeObject), // Target sel_getUid('image:didFinishSavingWithError:contextInfo:'), // Selector from string nil); // No context With this call, once the user is prompted to give write access to their photos (if first time) and the OS saves the image (if allowed) our handler will be called with the result: procedure TCompletionTarget.saveImageCompletionHandler(image: UIImage; error: NSError; contextInfo: Pointer); begin if error <> nil then // Do on error else // Do on success end; Some things to note: - Not sure if the handler is called on the main or on a secondary thread, so take care of this. - If the user denies access on first prompt the OS will return "Unknown error" for that and all subsequent calls. The OS will not ask permission again on your behalf. - Given the above limitation a best approach would be using the PHPhotoLibrary framework, as this allows to ask permission and check its status if previously denied, but such framework it is not implemented in Delphi by default.
  4. Oh, I forgot about this one. I gave up on it last year due to how hard it was to setup and the poor results obtained. I hope to update to 12.3 soon so I can test this too. Not really an issue for me as my potential users all work in the same company so I can carefully instruct them to properly do this, but yes it can be a challenge for the ordinary Play Store user.
  5. alejandro.sawers

    Error x509 PA Server - Apple

    Your screenshot doesn't show the error you talk about, just a command run by PAServer. If you can post the error message as seen in the IDE you may have better chances of getting useful help. You can look for posts in this forum that match or are similar to your issue, e.g.:
  6. alejandro.sawers

    12.3 or 13/14 as next?

    "Get an exclusive first look at a very exciting and long-anticipated completely new secret preview version of your favorite IDE." What!?
  7. alejandro.sawers

    Recommended devices android testing

    Much like programming itself, it's ideal if you can cover corner cases, like high-end and low-end devices, or devices from different manufacturers and/or Android versions. My Android testing "lab" actually consists of: - Google Pixel 7a (high resolution, latest Android patches including betas) - Samsung J2 Core (small screen, low resources, old Android versions) - Redmi Note 11 (mid point, main test device) This is because our app, on its simplicity, is expected to run on every Delphi-supported Android device possible, but most people (including myself years ago) can submit confidently to Play Store by testing with just a single physical device. Personally I think yes. Not only emulators are harder to run nowadays (I think modern, official Android emulators no longer run on x86 PCs) but also having full control of the devices is an availability bonus.
  8. alejandro.sawers

    Slow response on TButton click

    Didn't suggest to update Delphi version as usually (at least this is how I see it) someone using an old version either hasn't an active subscription or prefer stability over new features, and to update is a no-go in both cases. I'm curious if the working app is Skia-enabled and if that made any difference rather than the Delphi version, as I can't remember performance issues with 10.4.2 like the one shown here. Anyway, good to know it is solved.
  9. alejandro.sawers

    Slow response on TButton click

    Yeah, looks like a performance issue. Some things you could try (but before that please run more tests with other input controls, animations, tabs, timers, etc. so you know if the issue is visual or general performance): - Change your Form's Quality to HighPerformance - Switch to native controls - Test with Skia4Delphi - Try with third-party controls like Alcinoe or FGX (never tested these personally) However if the performance culprit is not merely visual (i.e. impacts the RTL) then the best option could be, if possible, to work with the device manufacturer / docs and check if something can be done at their OS level. Good luck.
  10. alejandro.sawers

    Slow response on TButton click

    Compiled the app on Delphi 10.4.2, tested on a Samsung J2 Core device (Android 8.1) and didn't notice any considerable lag/delay. Screen record below: rec3.mp4 Could be. Maybe some OS customization is causing FMX to perform poorly. Try to run an app with simple animations or content scroll.
  11. alejandro.sawers

    Delphi 12.1 CE with Android 14

    A common issue when compiling the same Android project between Delphi versions is that system libraries change, but the project doesn't update them automatically (by design apparently) so try that first. Also check if your project has custom versions of Delphi units and delete/update them as these can be a source of incompatibility issues.
  12. alejandro.sawers

    Delphi 12.1 CE with Android 14

    There are multiple issues here, but let's start with this one: From Android 11 onwards the storage permissions model has changed. Please see the official documentation about WRITE_EXTERNAL_STORAGE and, depending on your app's specific needs, you should not have problem on finding and implementing an alternate solution for modern Android versions.
  13. alejandro.sawers

    Installing the Android SDK/NDK

    You can safely ignore the warning as long as the command completes successfully. That's expected as the command fixes issues with the SDK, not with the NDK. Given that you copied SDK/NDK files from another machine and also updated from 11.2 to 11.3 (and your NDK seems to be missing now) your best bet would be reinstall Delphi from scratch and only then apply the command-line (if needed at all of course). It is not. The link contains a workaround just in case you decide to update to Delphi 12 and use the offline ISO installer to do so. It also contains notes for several platforms so look carefully.
  14. alejandro.sawers

    Installing the Android SDK/NDK

    I remember the Android SDK installation failing here and there, sometimes for unknown reasons. Luckily I have and old VM with Delphi 11.1 installed and it seems that the Android SDK also failed here (red underline is mine): If this is how your installation looks then doing a command-line install of the missing tools should solve the issue. On the SDK folder you should have a "cmdline-tools" folder, go inside to "latest\bin" and locate "sdkmanager.bat". Open a command line window in the folder that contains "sdkmanager.bat" and run a command like this one (note the versions of "build-tools" and "platforms" on red that your IDE demands and adjust the command accordingly): sdkmanager.bat --install "build-tools;30.0.3" "platform-tools" "platforms;android-30" After the command completes refresh the SDK Manager page. Unless you use the ISO installer, which causes a very similar issue but easier to fix.
  15. alejandro.sawers

    New patch is coming ?

    Seems like the NDK is being bumped to r27, which aligns to the official recommendations to support 16 KB page size Android devices in the near future. But it could also be just a coincidence.
  16. alejandro.sawers

    Delphi 12.2 Patch 1

    I think I will skip 12.2 Patch 1 because RSS-1840 was the only issue resolved with significant impact for me but there is a good enough workaround for 12.2 already, so reinstalling everything (that I have compiled with 12.2) is not worth the hassle right now. Waiting for 12.3 instead.
  17. alejandro.sawers

    Delphi 12.2 TMEMO - indexoutofbounds

    Just as a follow-up the workaround posted by @Borni has the side-effect of sending the caret to the end of the line when deleting a character using the soft keyboard, so I ended up changing this: To this: FTextView.setSelection(SelStart); Additionally there is another exception thrown when moving the caret with selected text to a line with less characters than the current selection (this happens on Samsung and non-Samsung devices alike). To mitigate that I had to add a couple of lines just before the if SelEnd - SelStart > 0 then check (line 1953) in the same procedure: // Normalize selection indexes SelStart:=Min(SelStart, JCharSequenceToStr(FTextView.getText).length); SelEnd:=Min(SelEnd, JCharSequenceToStr(FTextView.getText).length);
  18. alejandro.sawers

    Delphi 12.2 and MacOS Sequoia (15.0) : No provisioning profile

    As @Dave Nottage says this is a change introduced on macOS 15, most specifically a "fix" for XCode 16. Alternatively to Dave's solution, if there is no Apple ID linked to Xcode and you can't/don't want to link it you could also copy all the profiles from the old location to the new one: cp -R ~/Library/MobileDevice/Provisioning\ Profiles ~/Library/Developer/Xcode/UserData This was tested on a Mac with no profiles installed on the new folder whatsoever. This command shows on the PAServer terminal with verbose mode enabled, but its output is consumed internally by PAServer and not printed. You can always run the same command on another Terminal to explore the output.
  19. alejandro.sawers

    Android 5 and Firebase support

    Even though Delphi 12.x officially only supports Android 10+ devices as targets its actually possible to compile for lower Android versions with some tweaks on the NDK and the app Manifest. So far, so good it works as expected, but seems like there is an incompatibility when trying to add Firebase Messaging support and running it on an Android 5 device (i.e. API level 21, the lowest supported so far) : java.lang.NoSuchMethodError: No virtual method detectResourceMismatches()Landroid/os/StrictMode$ThreadPolicy$Builder; ... at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:264) at com.embarcadero.firebase.provider.FirebaseInitProvider.onCreate(FirebaseInitProvider.java:67) Effectively detectResourceMismatches() was introduced later, on API level 23, so this explains the crash at app startup on Firebase initialization. Now what puzzles me is while Firebase docs claim to offer support to Android versions as low as API level 19 (4.4), Firebase on Delphi calls an API level 23 method on initialization. By the way the same docs also say that "some products might have stricter requirements", so to be sure I checked the Release Notes to see if Messaging requires a higher API level to run, but apparently API level 19 is OK for the Firebase libraries included with Delphi 12.2: For now I'm disabling automatic Firebase initialization for Android 5 devices to avoid the startup crash (using the tools:node method didn't work, removing the <%provider%> tag from the Manifest template did). Hope a workaround (maybe downgrading some Firebase dependencies) is found before having to drop the Lollipop 🍭.
  20. alejandro.sawers

    Delphi 12.2 TMEMO - indexoutofbounds

    Put my hands on a Samsung A12 and can confirm the issue when pressing the return key: Testing on a Redmi Note 11 doesn't cause the exception, but by @havrlisan's comment it does happen when tapping on the memo to move the caret from a non-empty line to an empty one. This change seems to solve the issue on both Samsung and non-Samsung devices.
  21. alejandro.sawers

    Delphi 12.2 TMEMO - indexoutofbounds

    A quick test on a Delphi 12.2 blank FMX app with only a TMemo, compiled for Android 64, running on an Android 13 device doesn't show such error. Maybe test with a blank project to discard issues with your Delphi/Android SDK installation.
  22. alejandro.sawers

    Android SDK incomplete in 12.2 ?

    If you are using the offline ISO installer then you might need to reinstall the Android SDK alone.
  23. alejandro.sawers

    Delphi 12.2 available for download

    Seems like the issue with Android SDK when using ISO installer is still present on the latest ISO. The same workaround as for the 12.1 ISO still works.
  24. alejandro.sawers

    Kasti for iOS + Firebase Cloud Messaging issue

    I think the best you could have done is to post in advance what you have tried to do and how far you reached on your implementation, along with technical details as what Delphi version you use, if you test on device or simulator, etc. Anyway the best you could do to find the culprit on your own is to test with the Kastri supplied demo and/or a blank project, then: - If that works check what is different between the working project and your old project. - If that doesn't work then the issue could be elsewhere (Firebase project config, APN certificates, FCM backend giving errors, etc.)
  25. While this could frustrate some users, the truth is that approximate location access is not suited for most geolocation applications/features. Now if the user has given a incorrect location level access to the app (probably by mistake) it should inform the user so the permission level is corrected before accessing the features. Now for Delphi FMX apps this is trivial in Android as there are two separate permissions for approximate and precise location access and a simple query helps to determine the access level granted. The culprit is iOS, as since iOS 14 the accuracy authorization level is separated from the location authorization status itself, and apparently there is no way to access such value from user code (accuracyAuthorization is a CLLocationManager instance property but such instance is buried on the implementation section of System.iOS.Sensors.pas). So before patching this file and fighting the compiler about dependent units "compiled with another version of...", all without knowing if this would work at the end, I would like to know if somebody found another way to achieve this.
×