Jump to content

Yaron

Members
  • Content Count

    286
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Yaron


  1. We all knew it would come this August, but now the Google Play store is showing warning notifications on new uploads:

     

     
    Quote

     

    Warning

    This release is not compliant with the Google Play 64-bit requirement

    The following APKs or App Bundles are available to 64-bit devices, but they only have 32-bit native code: 9.

    From August 1, 2019 all releases must be compliant with the Google Play 64-bit requirement.

    Include 64-bit and 32-bit native code in your app. Use the Android App Bundle publishing format to automatically ensure that each device architecture receives only the native code it needs. This avoids increasing the overall size of your app. Learn More

     

     

    And to top it off, there's a new warning that I have no idea how to address (if it's even possible) with Delphi:

     
    Quote

     

    Unoptimized APK

    Warning:

    This APK results in unused code and resources being sent to users. Your app could be smaller if you used the Android App Bundle. By not optimizing your app for device configurations, your app is larger to download and install on users' devices than it needs to be. Larger apps see lower install success rates and take up storage on users' devices.

    Resolution:

    Use the Android App Bundle to automatically optimize for device configurations, or manage it yourself with multiple APKs.

     

     

    • Sad 2

  2. I am writing a remote control App that controls a PC.

     

    I am sending commands over TCP/IP each time a user clicks a UI button and at the same time, listening to responses to my commands.

    Presently, I am getting responses in the background "reading" thread and sending the command in the main thread.

    After reading your comments I realize my issue is further complicated, as your recommend not calling any TCP/IP function at all in my main thread, which means my Read function can't be blocking at all, otherwise the user will experience input-lag.

     

    Is it safe to call "IdTCPClient.IOHandler.WriteLn" in the main thread? If not, what is the best approach to check if there is data waiting without blocking?


  3. I am trying to create a really simple TCP/IP connection to a server using Indy on Android.  All the communication between the client and server is text based.

     

    I tried adjusting the code on Remi's answer from this thread to my needs:

    https://stackoverflow.com/questions/17372366/delphi-indy-tidtcpclient-reading-data

     

    However, what happens is that "FConn.IOHandler.ReadLn;" is blocking (at least under Android), so when the App closes and I try to terminate the thread, calling the thread's "WaitFor" method triggers a freeze as the thread never leaves the blocking "ReadLn" and never terminates.

     

    Is there a way to instantly stop ReadLn from waiting so the thread could terminate cleanly?  Or should I use "FConn.IOHandler.ReadBytes" instead?

     

    P.S.

    I read this thread:

    https://stackoverflow.com/questions/12507677/terminate-a-thread-and-disconnect-an-indy-client

     

    And in it Remy writes that "Disconnecting the client will cause ReadLn() to raise an exception inside the thread.", which is not the case for me under Android (I'm trying to catch the exception and write a log entry when it triggers, but nothing gets written).

    I also tried wrapping the disconnect method in a "try except" block, but it's not triggering any exception.

     

    The code I'm using:

    
    procedure TMainForm.CreateTCPIPConnection;
    var
      B : Boolean;
    begin
      IdTCPClient.Host := AddressEdit.Text;
      IdTCPClient.Port := StrToIntDef(PortEdit.Text,4769);
    
      B := False;
      Try
        IdTCPClient.Connect;
      except
        on E: Exception do
        Begin
          B := True;
          {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP connect exception : '+E.Message);{$ENDIF}
        End;
      end;
    
      If B = False then
      Begin
        If Assigned(ZPReadThread) = False then
        try
          ZPReadThread        := TReadingThread.Create(IdTCPClient);
          ZPReadThread.OnData := DataReceived;
          ZPReadThread.Start;
        except
          on E: Exception do
          Begin
            IdTCPClient.Disconnect;
            {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP exception creating read thread : '+E.Message);{$ENDIF}
          End;
        end;
      End;
    end;
    
    
    procedure TReadingThread.Execute;
    begin
      {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread created');{$ENDIF}
      while not Terminated do
      begin
        {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread ReadLn (before)');{$ENDIF}
        Try
          FData := FClient.IOHandler.ReadLn;
        Except
          on E: Exception do
          Begin
            {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP IOHandler.ReadLn exception : '+E.Message);{$ENDIF}
          End;
        End;
        //FClient.IOHandler.ReadBytes(AData, sizeof(TWaveFormSample), False);
        {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread ReadLn (after)');{$ENDIF}
        if (FData <> '') and Assigned(FOnData) then
          Synchronize(DataReceived);
        //Sleep(1);
      end;
      {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread about to terminate');{$ENDIF}
    end;
    
     
    
    procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
    
    begin
    
      If IdTCPClient.Connected = True then
      Begin
        try
          IdTCPClient.Disconnect;
        except
          on E: Exception do
          Begin
            {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP Disconnect exception : '+E.Message);{$ENDIF}
          End;
        end;
      End;
    
      if Assigned(ZPReadThread) then
      Begin
        {$IFDEF TRACEDEBUG}AddDebugEntry('Terminating Read thread');{$ENDIF}
        ZPReadThread.Terminate;
        {$IFDEF TRACEDEBUG}AddDebugEntry('Waiting for read thread termination');{$ENDIF}
        ZPReadThread.WaitFor;
        {$IFDEF TRACEDEBUG}AddDebugEntry('Finished waiting for read thread termination');{$ENDIF}
        FreeAndNil(ZPReadThread);
      End;
    
    end;
    
    


  4. 1 minute ago, Uwe Raabe said:

    In fact, you can even have both:

    The Old Component Palette is simply a toolbar which can be made visible or hidden via  View - Toolbars - Component.

    The New Component Palette is a tool window that can be reached via View - Tool Windows - Palette.

    Make sure to save your layout to make your changes permanent.

    For me "View - Tool Windows - Palette" shows a new project selection palette window (similar to File -> New) and not the components palette.


  5. I am trying to write a very basic Android app that will receive a share from the YouTube app and show the data in a memo.

     

    I tried basing it on Embarcadero's Receive Intent sample:

    https://sourceforge.net/p/radstudiodemos/code/HEAD/tree/branches/RADStudio_Seattle/Object Pascal/Mobile Snippets/AndroidIntents/ReceiveIntent/

     

    The only thing I did to the sample was to change a line in AndroidManifest.template.xml from:

    Quote

    <data android:mimeType="text/pas" />

     

    To:

    Quote

    <data android:mimeType="text/plain" />

     

    However, I'm encountering two issues:

     

    1. After installing the app on an Android device, it isn't listed in the app list.  I can see it on the "application manager" settings page, but not in the main app list.

    2. YouTube is not listing the app as an option on the share dialog.

     

    How can I resolve these 2 issues?


  6. I actually posted this question on stack overflow a while back, got what I thought was a working answer but over time realized that on different devices, waiting for "onIdle" doesn't actually work.

     

    Here's the background, my app on first-load does some time-consuming (3-8 sec) pre-calculations so subsequent runs would be much faster.  During this processing period, I want to show a "loading %" track-bar.

     

    However, for the life of me, I haven't been able to find the exact moment my form is visible and responsive for action.  I tried different approaches:

    1. waiting for "OnActivate" event.

    2. Implementing IFMXApplicationEventService.SetApplicationEventHandler and waiting for "TApplicationEvent.BecameActive".

    3. Waiting for "TApplicationEvent.BecameActive" to trigger and then waiting for 3 "OnIdle" events to trigger (2 OnIdle events were not enough for my Galaxy Note 4 device).

     

    Only #3 sort of worked on most devices using Delphi 10.2.3, but then when I upgraded to Delphi 10.3.1 even that stopped working (my progress bar shows up but the screen stops updating, so the bar remains on 0% until the pre-calculation function completes, even when calling Application.ProcessMessages after each update and no other code running in the background).

     

    Is there a better solution to know the exact moment my app will start responding to screen updates on launch under Android?

     


  7. @Dave Nottage

    I can't really debug since I constantly suffer from the "Unable to start gdbserver on port '64311'. Port is already in use.", so instead I've added many more debug output lines.

     

    I finally figured out what was going on, I was creating my bitmap inside a function that was triggered by a timage-clicked, that function then called the permission request with an anonymous function.

    However, once the anonymous function was triggered, the bitmap var was no longer valid.

    I fixed the issue by creating the bitmap within the anonymous function.

     


  8. I am trying to save an image to the photo gallery using Delphi 10.3 and Android 6+

     

    However, when the user accepts the access request prompt on the very first call, my entire app restarts all on it's own, is there any way to disable this behavior so my app doesn't restart?

     

     

    I implemented the code based on this blog post:

    http://blong.com/Articles/AndroidPermissions/DelphiAppPermissions.htm

     

    After calling (on form create):

      FPermission_READ_EXTERNAL_STORAGE  := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE);
      FPermission_WRITE_EXTERNAL_STORAGE := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
    

     

    I am calling this code to show the prompt and save the image:

          // Request permission
          PermissionsService.RequestPermissions([FPermission_WRITE_EXTERNAL_STORAGE, FPermission_READ_EXTERNAL_STORAGE],
            procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
            begin
              if (Length(AGrantResults) = 2) and (AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted) then
              Begin
                { Save file }
                BaseFolder := System.IOUtils.TPath.GetSharedPicturesPath;
                If DirectoryExists(BaseFolder) = True then
                Begin
                  PIKAFolder := BaseFolder+System.IOUtils.TPath.DirectorySeparatorChar+clientGameName;
                  If DirectoryExists(PIKAFolder) = False then ForceDirectories(PIKAFolder);
    
                  PIKAFile := PIKAFolder+System.IOUtils.TPath.DirectorySeparatorChar+clientGameName+'_'+ReplaceStr(ReplaceStr(DateTimeToStr(Now),':','.'),'/','.')+saveImageFileExt;
                  Try
                    MyImage.SaveToFile(PIKAFile);
                  Except
                    clientFadingMessage := strErrorSavingPicture;
                  End;
                  If FileExists(PIKAFile) = True then clientFadingMessage := strPictureSaved else If clientFadingMessage = '' then clientFadingMessage := strErrorSavingPicture2;
                End
                Else clientFadingMessage := strPictureFolderNotFound;
              End
                else
              begin
                clientFadingMessage := strErrorSavingPicture;
              end;
            end
          );

     


  9. On 2/4/2019 at 1:06 PM, Cristian Peța said:

    If adb connection is not working then installing a Log visualizer from the market is the easiest solution to see the log.

    Can you post a link to one, I tried a search on the google play store and it only came back with text viewers.

    On 2/5/2019 at 5:46 PM, John Kouraklis said:

    Have you tried a simple project that does nothing? 

    Yes, created a new multi-platform project, compiled & deployed it without any changes, installed the APK on Nox and it crashes with "Project1 keeps stopping" instantly when executed.


  10. On 2/1/2019 at 3:08 AM, John Kouraklis said:

    How did you manage to make Delphi recognise the emulator? I've got a similar situation and cant make it see the emulator. 

     

    And something else? Do you use any virtual machines or directly on the main PC?

     

    I am not trying to use NOX as the debugger, I'm trying to get it to run my compiled APKs simply by dragging the APK onto the NOX window which installs just fine.

    But as soon as I try to run any Delphi 10.3 app on NOX, it instantly closes with an error message that the app has closed.

     

    And I use it on my main PC, no virtual machines (other than NOX of course)

     


  11. It seems that Delphi 10.3 generated APKs are not compatible with the NOX emulator running Android 7.

     

    The moment I try running the APK, I get a message that the application closed.

     

    This happens with every APK I generate (e.g. https://github.com/bLightZP/ElegantCalculator).

    Trying to debug the issue, it seems that my first line of code is not even executed before the app closes.

     

    Any ideas?

×