3delite 2 Posted June 2, 2022 (edited) Hi! Android app. seems working fine in debug or release (Development) mode on my Android device. But if I upload the AAB file to Google Play Store and install it from there it exits on startup. Not sure if it's a crash I have very little experience with Android. The project is from the XE5 era. Tried: - Deleted the manifest file, so it was re-created by Delphi - Did a "Revert system files to default" - Did a "Revert to default" in Deployment Google Play Store page: https://play.google.com/store/apps/details?id=com.embarcadero.MP4StreamEditorClient As I wrote it seems working fine if I start it through Delphi+USB and also if I start it after it has been installed by Delphi, just the Install and start from Play Store does not work. Any ideas? Thank you! 3delite Edited June 2, 2022 by 3delite Share this post Link to post
Pieter Bas Hofstede 14 Posted June 3, 2022 Hi, what you could try is making a new FMX-application and after that add all the units of the old dpk to the new dpk. EMB have added a lot of config to the dproj which isn't (of at least wasn't till 10.4.2) automatically added when you upgrade to a newer Delphi-version. I know you'll have to set a lot of config again, but give it a try at least. Share this post Link to post
Dave Nottage 557 Posted June 3, 2022 12 hours ago, 3delite said: install it from there it exits on startup For me, it asked for permissions (which I granted), then restarts over and over, presenting a toast related to permissions being granted. Without knowing exactly the code is doing during startup, it's going to be difficult to diagnose. I suggest moving as much code as you can out of FormCreate (if you use that event) or the main forms constructor (if you have overridden it), and call it later. Share this post Link to post
Pieter Bas Hofstede 14 Posted June 3, 2022 39 minutes ago, Pieter Bas Hofstede said: Hi, what you could try is making a new FMX-application and after that add all the units of the old dpk to the new dpk. EMB have added a lot of config to the dproj which isn't (of at least wasn't till 10.4.2) automatically added when you upgrade to a newer Delphi-version. I know you'll have to set a lot of config again, but give it a try at least. I've even had a situation at one day of an existing project, delete dproj+everything but keep the dpk, when opening the dpk Delphi generated a different dproj+deployment comparing to a complete new FMX-application-setup. Please be aware of that. Share this post Link to post
3delite 2 Posted June 4, 2022 Thank you very much for the suggestions! It came to my mind that, as the permission request is called, it is in FormCreate(), so the code does get there. I have this in FormCreate() after that: if NOT LoadBASS then begin //Showmessage('Error loading BASS.'); Halt; end; And LoadBASS is: function LoadBASS: Boolean; var DocDir: string; BASSLibraryHandle: THandle; BASSMixLibraryHandle: THandle; BASSFXLibraryHandle: THandle; begin Result := False; DocDir := IncludeTrailingPathDelimiter(System.IOUtils.TPath.GetLibraryPath); //* BASS BASSLibraryHandle := LoadLibrary(PChar(DocDir + 'libbass.so')); if BASSLibraryHandle = 0 then begin Exit; end; if BASSLibraryHandle <> 0 then begin @BASS_Init := GetProcAddress(BASSLibraryHandle, ('BASS_Init')); @BASS_StreamCreateFile := GetProcAddress(BASSLibraryHandle, ('BASS_StreamCreateFile')); @BASS_ChannelPlay := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelPlay')); @BASS_ErrorGetCode:=GetProcAddress(BASSLibraryHandle, ('BASS_ErrorGetCode')); @BASS_Free:=GetProcAddress(BASSLibraryHandle, ('BASS_Free')); @BASS_GetCPU:=GetProcAddress(BASSLibraryHandle, ('BASS_GetCPU')); @BASS_SetConfig:=GetProcAddress(BASSLibraryHandle, ('BASS_SetConfig')); @BASS_GetConfig:=GetProcAddress(BASSLibraryHandle, ('BASS_GetConfig')); @BASS_GetDevice:=GetProcAddress(BASSLibraryHandle, ('BASS_GetDevice')); @BASS_ChannelGetInfo:=GetProcAddress(BASSLibraryHandle, ('BASS_ChannelGetInfo')); @BASS_MusicLoad := GetProcAddress(BASSLibraryHandle, ('BASS_MusicLoad')); @BASS_MusicFree := GetProcAddress(BASSLibraryHandle, ('BASS_MusicFree')); @BASS_StreamFree := GetProcAddress(BASSLibraryHandle, ('BASS_StreamFree')); @BASS_ChannelBytes2Seconds := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelBytes2Seconds')); @BASS_ChannelGetLength := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelGetLength')); @BASS_ChannelGetPosition := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelGetPosition')); @BASS_ChannelStop := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelStop')); @BASS_ChannelPause := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelPause')); @BASS_PluginLoad := GetProcAddress(BASSLibraryHandle, ('BASS_PluginLoad')); @BASS_ChannelSetSync := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelSetSync')); @BASS_GetDeviceInfo := GetProcAddress(BASSLibraryHandle, ('BASS_GetDeviceInfo')); @BASS_ChannelSetPosition := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelSetPosition')); @BASS_ChannelRemoveSync := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelRemoveSync')); @BASS_ChannelSeconds2Bytes := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelSeconds2Bytes')); @BASS_ChannelLock := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelLock')); @BASS_StreamCreateURL := GetProcAddress(BASSLibraryHandle, ('BASS_StreamCreateURL')); @BASS_Stop := GetProcAddress(BASSLibraryHandle, ('BASS_Stop')); @BASS_ChannelGetTags := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelGetTags')); @BASS_ChannelSetFX := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelSetFX')); @BASS_ChannelRemoveFX := GetProcAddress(BASSLibraryHandle, ('BASS_ChannelRemoveFX')); @BASS_FXSetParameters := GetProcAddress(BASSLibraryHandle, ('BASS_FXSetParameters')); @BASS_FXGetParameters := GetProcAddress(BASSLibraryHandle, ('BASS_FXGetParameters')); Result := True; end; //* BASSMix BASSMixLibraryHandle := 0; if FileExists(DocDir + 'libbassmix.so') then begin BASSMixLibraryHandle := LoadLibrary(PChar(DocDir + 'libbassmix.so')); if BASSMixLibraryHandle = 0 then begin Exit; end; end else begin Showmessage('Error loading: ' + DocDir + 'libbassmix.so'); end; if BASSMixLibraryHandle <> 0 then begin @BASS_Mixer_StreamCreate := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_StreamCreate')); @BASS_Mixer_StreamAddChannel := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_StreamAddChannel')); @BASS_Mixer_ChannelFlags := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelFlags')); @BASS_Mixer_ChannelSetPosition := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelSetPosition')); @BASS_Mixer_ChannelGetPosition := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelGetPosition')); @BASS_Mixer_ChannelGetData := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelGetData')); @BASS_Mixer_ChannelSetSync := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelSetSync')); @BASS_Mixer_ChannelRemoveSync := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelRemoveSync')); @BASS_Mixer_ChannelSetMatrix := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelSetMatrix')); @BASS_Mixer_ChannelSetEnvelope := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelSetEnvelope')); @BASS_Mixer_ChannelRemove := GetProcAddress(BASSMixLibraryHandle, ('BASS_Mixer_ChannelRemove')); Result := True; end; //* BASS_FX BASSFXLibraryHandle := LoadLibrary(PChar(DocDir + 'libbass_fx.so')); if BASSFXLibraryHandle = 0 then begin Exit; end; if BASSFXLibraryHandle <> 0 then begin @BASS_FX_GetVersion := GetProcAddress(BASSFXLibraryHandle, ('BASS_FX_GetVersion')); BASS_FX_GetVersion; Result := True; end; end; Could it be possible that the folder is invalid? The needed SO files are in "library\lib\arm64-v8a\" and this is not existing when using an AAB? DocDir := IncludeTrailingPathDelimiter(System.IOUtils.TPath.GetLibraryPath); Attached a screenshot of the deplyment page. Does the AAB format change the folder structure in some way? Share this post Link to post
Dave Nottage 557 Posted June 4, 2022 4 hours ago, 3delite said: Does the AAB format change the folder structure in some way? Whatever the case, the BASS libraries are not ending up in the app. I "pulled" the APK after installing the app, and there's no lib folder: Share this post Link to post
3delite 2 Posted June 6, 2022 (edited) That's strange! Managed to fix it though. The BASS .so files were not found with the TPath.GetLibraryPath function. While Googleing for this issue there seems to be some kind of new system for loading the .so files and the solution is to simply not specify a path for the LoadLibrary() call, the Android system picks the needed folder. So just use: BASSLibraryHandle := LoadLibrary(PChar('libbass.so')); This now seems working perfectly for both .apk and .aab. This goes for all the .so files that are loaded with LoadLibrary(). And in deployment the .so files are all remote path "library\lib\arm64-v8a\" (same as before for 64 bit). Thank you very much for helping! If it would be possible to check once again the install from Google Play Store (I updated the package, that seems working fine here now)? Thank you! 3delite Edited June 6, 2022 by 3delite 1 Share this post Link to post
vfbb 285 Posted June 6, 2022 (edited) @3delite Loading dynamic libraries on Android is not that trivial, you will still have problems on some devices of some manufacturers. Here are 3 main tips: 1) Filename: ALWAYS suffix "lib", like "libbass.so" 2) Deployment: On 32bit, the remote path "library\lib\armeabi-v7a\" On 64bit, the remote path "library\lib\arm64-v8a\" Also on 64bit, add the 32bit binary with the remote path "library\lib\armeabi-v7a\" and the condition "'$(AndroidAppBundle)''==''true'" (with the quotes). The condition you can only change via ToolsApi or manually in .dproj. See how we do it: https://github.com/skia4delphi/skia4delphi/blob/eed4afbf8a34137a9bfa308bcb5ef87cee84abcb/Source/VCL/Designtime/Skia.Vcl.Designtime.ProjectMenu.pas#L219-L221 3) Loading: First try to load using only the filename, and in case of failure use the library path + filename. See how we do it: https://github.com/skia4delphi/skia4delphi/blob/eed4afbf8a34137a9bfa308bcb5ef87cee84abcb/Source/Skia.API.pas#L2119-L2124 Edited June 6, 2022 by vfbb Share this post Link to post
3delite 2 Posted June 9, 2022 Thank you very much for the detailed tips! Ok, so I changed the code to: BASSLibraryHandle := LoadLibrary(PChar('libbass.so')); if BASSLibraryHandle = 0 then begin BASSLibraryHandle := SafeLoadLibrary(TPath.Combine(TPath.GetLibraryPath, 'libbass.so')); if BASSLibraryHandle = 0 then begin Showmessage('Error loading libbass.so.'); Exit; end; end; if BASSLibraryHandle <> 0 then begin @BASS_Init := GetProcAddress(BASSLibraryHandle, ('BASS_Init')); ... BTW. I downloaded the Skia4Delphi package a couple of weeks ago, seems very cool stuff. I did not have time to check it though, but seems professional. Thank you very much for helping with this issue! 1 Share this post Link to post
TurboMagic 92 Posted November 2, 2023 On 6/6/2022 at 1:44 PM, vfbb said: 2) Deployment: On 32bit, the remote path "library\lib\armeabi-v7a\" On 64bit, the remote path "library\lib\arm64-v8a\" Also on 64bit, add the 32bit binary with the remote path "library\lib\armeabi-v7a\" and the condition "'$(AndroidAppBundle)''==''true'" (with the quotes). The condition you can only change via ToolsApi or manually in .dproj. See how we do it: https://github.com/skia4delphi/skia4delphi/blob/eed4afbf8a34137a9bfa308bcb5ef87cee84abcb/Source/VCL/Designtime/Skia.Vcl.Designtime.ProjectMenu.pas#L219-L221 I also struggle to load a .so. In my case the .so was created in Delphi for testing purposes. I tried to follow your idea with the deployment but I didn't fully understand this yet. Is this only relevant if I'm building an .aab later on? I'm currently still struggeling with a normal apk / debugger / debug build. I'm currently using an Android 11 device but will test on a Android 13 device in a few minutes. On the device used the first call to SafeLoadLibrary results in a Segmentation fault(11) crash. Here's my code: procedure Tf_Main.b_CalcClick(Sender: TObject); var Handle : HMODULE; s : string; begin Memo1.Lines.Clear; s := TPath.Combine(TPath.GetLibraryPath, 'libSO_Test.so'); if System.SysUtils.FileExists(s) then Memo1.Lines.Add('Exists'); Handle := SafeLoadLibrary('libSO_Test.so'); Memo1.Lines.Add('Handle1: ' + Handle.ToString); if (Handle = 0) then Handle := SafeLoadLibrary(s); Memo1.Lines.Add('Handle2: ' + Handle.ToString); if (Handle <> 0) then begin try FDoAdd := GetProcAddress(Handle, PChar('DoAdd')); if (@FDoAdd = nil) then Memo1.Lines.Add('Failure loading proc (is nil)') else begin l_Result.Text := FDoAdd(tf_Summand1.Text.ToInteger, tf_Summand2.Text.ToInteger).ToString; FDoAdd := nil; Memo1.Lines.Add('Success'); end; finally FreeLibrary(Handle); end; end else Memo1.Lines.Add('SO handle is invalid'); end; Any idea? Share this post Link to post
vfbb 285 Posted November 2, 2023 10 hours ago, TurboMagic said: I tried to follow your idea with the deployment but I didn't fully understand this yet. Is this only relevant if I'm building an .aab later on? Yes, this is relevant only for the .aab generation. Note: you can’t change the ‘condition’ on IDE side, you should open the dproj and add it manually. See one dproj with that: https://github.com/skia4delphi/skia4delphi/blob/eed4afbf8a34137a9bfa308bcb5ef87cee84abcb/Samples/Demo/FMX/Projects/RAD%20Studio%2011%20Alexandria/Skia4Delphi.dproj#L1182 Share this post Link to post