Перейти к содержанию
Fire Monkey от А до Я

Евгений Корепов

Пользователи
  • Постов

    738
  • Зарегистрирован

  • Посещение

  • Победитель дней

    100

Сообщения, опубликованные Евгений Корепов

  1. В 04.08.2019 в 11:11, Евгений Корепов сказал:

    При публикации приложения iOS получаю ошибку при использовании JVEsuite :

    Кто нибудь сталкивался с подобным? Как победить?

    Ответил мне автор JVEsuite, дай бог ему здоровья!

    Цитата

    Просто уберите “-weak_framework IOSurface" из Linked Option и попробуйте
    загрузить еще раз - должно сработать.


    Эпл успешно прожевал приложение и загрузил сборку.

  2. 15 минут назад, ivyl сказал:

    "Android One — линейка смартфонов, использующих немодифицированый Андроид". Отсюда, получив рут и удалив все лишнее барахло от производителя - получим А.Ван. Будет ли работать приложение со статическими разрешениями на телефоне А.Ван с 6-м Андроидом? Нет. Будут ли работать простые уведомления на телефоне А.Ван с Орео? Нет. 

    "А.Ван" это что? Трудно понимать ход мыслей человека коверкающего не сложные слова. 

    Видимо имеется ввиду Android One? Я вас разочарую - получением рута и удалением софта от производителя вы не получите чистый андроид. Вы получите все  тот же андроид который установил (и возможно неким образом модифицировал) производитель устройства. Ну и конечно не будет никаких обновлений версий и ежемесячных обновлений безопасности.

    Не знаю что у вас за проблемы с уведомлениями и разрешениями на рутованных и превращенных в "А.Ван" устройствах. На Android One уведомления отлично работаю, разрешения работают согласно документации.

    Почему вы считаете что я нахваливаю Android One? Я всего лишь рекомендую. И откуда у вас сведения что телефон с Android One "не сможет"? Судя по вашей ненависти к Xiaomi и Android One, вы никогда не пробовали ни то, ни другое. Откуда тогда этот бесценный опыт? Громкие, безапелляционные заявления признак небольшого ума...

    Из всего зоопарка моих устройств, Mi A1 служит мне дольше всех, третий год. С ним я получил бесценный опыт попробовав 7, 8 и теперь уже 9 андроид. Видите, мое заявление "не один год" основывается на личном продолжительном опыте, а не на эмоциях и ненависти к чему либо.

    И не смешите про "симметричный ответ" ? На мою короткую, обоснованную и не навязчивую рекомендацию автору топика, вы расписали тут целую теорию заговора, целью которой видимо является уничтожение человечества. ?

    P.S. Кстати к седьмому классу мы успешно подготовились. Школьная форма для дочери куплена. Тетради, ручки, карандаши и линейки тоже. Удивительно как быстро растут дети, только вроде в первый класс пошла, а тут раз и уже седьмой на носу.

  3. При публикации приложения iOS получаю ошибку при использовании JVEsuite :

    Цитата

    ITMS-90338: Non-public API usage - The app links to non-public libraries in AppName: /System/Library/PrivateFrameworks/IOSurface.framework/IOSurface. If method names in your source code match the private Apple APIs listed above, altering your method names will help prevent this app from being flagged in future submissions. In addition, note that one or more of the above APIs may be located in a static library that was included with your app. If so, they must be removed. If you think this message was sent in error and that you have only used Apple-published APIs in accordance with the guidelines, send the app's Apple ID, along with detailed information about why you believe the above APIs were incorrectly flagged, to appreview@apple.com. For further information, visit the Technical Support Information at http://developer.apple.com/support/technical/

    Кто нибудь сталкивался с подобным? Как победить?

  4. Вот кусок кода из боевого приложения, достаточно разрешения на доступ к камере, больше никаких разрешений не надо. Надеюсь вам поможет.

    FScanCamera : TCameraComponent;

    FScanManager - не обращайте внимания, это распознавание QR кодов.

    ImageCamera : TImage; - картинка на форме где отображаются кадры с камеры

    Работа начинается с ScanStart()

    {$IFDEF MOBILE}
    // ***************************************************************
    // ****** Сканирование QR кода ******
    // ***************************************************************
    procedure TFormMain.ScanStart();
    var AppEventSvc: IFMXApplicationEventService;
        APermissionCamera : String;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(AppEventSvc)) then
        AppEventSvc.SetApplicationEventHandler(AppEvent);
    
      FScanFrameTake := 0;
      CButtonScan.Text:='Отменить сканирование';
    {$IFDEF IOS}
      ScanStarting();
    {$ENDIF IOS}
    {$IFDEF ANDROID}
      APermissionCamera := JStringToString(TJManifest_permission.JavaClass.CAMERA);
      PermissionsService.RequestPermissions([APermissionCamera], CameraPermissionRequestResult, ExplainReason);
    {$ENDIF ANDROID}
    end;
    
    procedure TFormMain.ScanStop();
    begin
      if Assigned(FScanCamera) then
      begin
        if FScanCamera.Active then
          FScanCamera.Active:=False;
        FScanCamera.Free;
      end;
    {
      if Assigned(FScanManager) then
      begin
        FScanManager.Free;
      end;
    }
      FScanInProgress := false;
      LayoutCamera.Height:=0;
      CButtonScan.Text:='Сканировать QR-код';
    end;
    
    {$IFDEF ANDROID}
    procedure TFormMain.CameraPermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
    begin
      if (Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted) then
      begin
        ScanStarting();
      end
      else
        TDialogService.ShowMessage('Сканирование QR-кода не возможно, требуемое разрешение не было дано')
    end;
    
    procedure TFormMain.ExplainReason(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
    begin
      TDialogService.ShowMessage('Приложению нужен доступ к камере для сканирования QR-кода ...',
        procedure(const AResult: TModalResult)
        begin
          APostRationaleProc;
        end)
    end;
    {$ENDIF ANDROID}
    
    procedure TFormMain.ScanStarting();
    begin
        FScanInProgress := false;
        if Not Assigned(FScanManager) then
          FScanManager:= TScanManager.Create(TBarcodeFormat.QR_CODE, nil);
        if Not Assigned(FScanCamera) then
          FScanCamera:=TCameraComponent.Create(Self);
        FScanCamera.OnSampleBufferReady:=ScanCameraSampleBufferReady;
        FScanCamera.Quality := FMX.Media.TVideoCaptureQuality.MediumQuality;
        FScanCamera.Active := false;
        FScanCamera.Kind := FMX.Media.TCameraKind.BackCamera;
        FScanCamera.FocusMode := FMX.Media.TFocusMode.ContinuousAutoFocus;
        FScanCamera.Active := True;
        LayoutCamera.Height:=LayoutCamera.Width;
    end;
    {
    procedure TFormMain.btnStopCameraClick(Sender: TObject);
    begin
    
    end;
    }
    
    procedure TFormMain.ScanCameraSampleBufferReady(Sender: TObject; const ATime: TMediaTime);
    begin
      TThread.Synchronize(TThread.CurrentThread, GetImageCamera);
    end;
    
    procedure TFormMain.GetImageCamera;
    var scanBitmap: TBitmap;
        ReadResult: TReadResult;
    begin
      FScanCamera.SampleBufferToBitmap(ImageCamera.Bitmap, True);
    
      if (FScanInProgress) then
        exit;
    
      { This code will take every 4 frame. }
      Inc(FScanFrameTake);
      if (FScanFrameTake mod 4 <> 0) then
        exit;
    
      scanBitmap := TBitmap.Create();
      scanBitmap.Assign(ImageCamera.Bitmap);
      ReadResult := nil;
    
    // There is bug in Delphi Berlin 10.1 update 2 which causes the TTask and
    // the TThread.Synchronize to cause exceptions.
    // See: https://quality.embarcadero.com/browse/RSP-16377?jql=project%20%3D%20RSP%20AND%20issuetype%20%3D%20Bug%20AND%20affectedVersion%20%3D%20%2210.1%20Berlin%20Update%202%22%20AND%20status%20%3D%20Open%20ORDER%20BY%20priority%20DESC
    
      TTask.Run(
        procedure
        begin
          try
            FScanInProgress := True;
            try
              ReadResult := FScanManager.Scan(scanBitmap);
            except
              on E: Exception do
              begin
                TThread.Synchronize(nil,
                  procedure
                  begin
                    LabelAPIKey.Text := 'Ключ доступа : ' + E.Message;
                  end);
                exit;
              end;
            end;
    
            TThread.Synchronize(nil,
              procedure
              begin
                if (ReadResult <> nil) then
                begin
                  if ProcessingAPIKeyHex(ReadResult.Text) then
                  begin
                    ScanStop();
                  end;
                end;
              end);
    
          finally
            ReadResult.Free;
            scanBitmap.Free;
            FScanInProgress := false;
          end;
    
        end);
    
    end;
    
    { Make sure the camera is released if you're going away. }
    function TFormMain.AppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
    begin
      case AAppEvent of
        TApplicationEvent.WillBecomeInactive,
        TApplicationEvent.EnteredBackground,
        TApplicationEvent.WillTerminate:
          if Assigned(FScanCamera) then
            FScanCamera.Active := false;
      end;
      Result:=True;
    end;

     

  5. 57 минут назад, ivyl сказал:

    А Орео вышел в 2017. Продолжать или дойдет наконец-то?

    Нет, дойдет, поясните пожалуйста:   Проект Android One был представлен в 2014, а Орео вышел в 2017, поэтому в строке "Build.VERSION_CODES.O" буква "О" означает Орео  -  вот для меня ход ваших мыслей неясен совсем, что это значит? Что Нибиру прилетит в четверг? ?

    57 минут назад, ivyl сказал:

    Нарциссизм излечим. Наверное.

    Ну я рад за вас )))

    1 час назад, ivyl сказал:

    Давайте, жду следующего сообщения с волнами вашего сочувствия. Это для меня так же важно, как и история о вашей оторванной ноге (или что там кто там вам оторвал). Заодно, ближе к сентябрю, расскажете как там перед шестым классом подготовка к линейке идет. Стишок хоть дали выучить?

    Аргументы закончились? Теперь оскорбления? Заметьте, даже готовясь к шестому классу (если честно, то к седьмому), я не позволяю себе оскорблять вас и обижать заявляя что вам не дадут выучить стишок (  Вот это было очень обидно.

  6. 44 минуты назад, Дмитрий Потапов сказал:

    В общем. Embarcadero решились таки исправить проблему с кнопками сами и теперь приложение у меня работает нормально, все кнопки с пульта отлавливаются и коды приходят, но все же бегло просмотрел файлы и сразу же наткнулся на то, что не все кнопки были добавлены, ибо у Google коды кнопок идут от 0 до 285, а вот Embarcadero добавили только от 0 до 221, не знаю, почему не добавили все.

    Используемая версия IDE: Rio 10.3.2

    Ну вот в этом вся Эмбаркадера ( Типа нам кнопки больше 221 точно не понадобятся. Ощущение что они не среду разработки делают, а какое то прикладное приложение для не очень умных пользователей.

    Спасибо за информацию!

  7. 3 часа назад, ivyl сказал:

    Конечно же, нет - это же тайна за семью печатями, доступная только избранным.

    В строке "Build.VERSION_CODES.O" буква "О" означает Орео. Погуглите каналы уведомлений.

    Выдумывайте перед зеркалом.
     

    Не утверждал. Найдите слово "только" в моем посте, потом выдумывайте.

    Нет. Объяснение (одно из) выше.

    Начинайте.

    "Android One" это не печенье Орео, это 

    Цитата

    линейка смартфонов, использующих немодифицированную операционную систему Android. Технические стандарты на их аппаратное и программное обеспечение созданы Google для обеспечения единообразного пользовательского опыта и повышения безопасности пользователей за счет частых обновлений и Google Play Protect. Проект Android One был представлен в 2014 году и изначально ориентировался на устройства начального уровня для развивающихся рынков, но позже был расширен и для других сегментов рынка.

    Источник https://ru.wikipedia.org/wiki/Android_One

    Форум присылает копии сообщений, даже если вы потом впопыхах его редактируете, все видят исходное сообщение:

    Цитата

    Выдумывайте перед зеркалом.
    если непонятно - не люблю, когда люди с умным видом рассказывают, что самый хороший телефон/компьютер/{нужное вставить} только потому, что оно есть у них. Отсылаю к той части своего предыдущего поста, где написано про 5 устройств, которые отлично определяются. 

    Удивительно как по моей фразе "Просто покупайте любой Xiaomi c Android One (чистый андроид)" вы определили что я печатал ее с умным видом (одновременно думая - он у меня есть, он самый лучший) ?

    Еще у меня есть HTC, Samsung, Dexp. На них я тоже тестирую приложения. И это меня не коробит, в отличие от вас. О! А еще у меня есть телефон на iOS, марки Apple. ?

    Вообщем я сочувствую вам...

    P.S. С интересом послушаю удивительную историю возникновения вашей ненависти к Xiaomi, думаю это будет захватывающе! Типа робот-пылесос Xiaomi оторвал вам ногу, или беспроводные наушники Xiaomi приказывают вам делать плохие вещи, или просто авторитетный пятиклассник сказал вам что Xiaomi гавно?

     

  8. 42 минуты назад, ivyl сказал:

    Отлично понял, что написал. В конкретно цитируемом посте:

    Так понятнее?
     

    В семье из 5 андроид устройств и (2-х эмуляторов, ха-ха) ни одного Кся и все они прекрасно определяются как Berlin`ом, так и Eclipse. Руки при подключении надо выравнивать, а потом хвалить свой телефон.
    И в качестве справки. Приложение с уведомлением, написанное с Build.VERSION.SDK_INT < Build.VERSION_CODES.O и прекрасно работающее на Ксяоми с API<= 25 (Нуга), совершенно ничего не уведомит на Асусе с Орео.

    Но, если приложение пишется только для телефона жены - то, само собой, "и так сойдет".

    Отсюда, 

    Так что сами

     

    Вы понимаете что такое "Android One" ? Погуглите. Вы несете какую то ересь. Утверждаете что приложение будет работать только на том устройстве, на котором вы его разрабатывали. Это бред. Если приложение работает на одном устройстве, то оно будет работать и на 99% остальных. Если у вас какая то ненависть к определенному производителю, то не вздумайте заходить на этом форуме в раздел разработки для iOS и macOS - там все запускают приложения на устройствах Apple! Ужас какой!  )))

    Вот вопрос уважаемого автора темы:

    Цитата

    Поделитесь, пожалуйста, кто какую марку телефона использует для беспроблемной сборки стенда и какая на нем версия андроида?

    А вот в чем вы меня обвиняете:

    Цитата

    При том, что был указана конкретная ТМ.

     

    Заметьте что кроме вас тут никто не бросается обвинениями, все уважают мнение друг друга и до последнего времени форуме была дружеская обстановка. Так что предлагаю начать сначала, просто держите своих тараканов при себе и мы подружимся )))

  9. 3 часа назад, #WAMACO сказал:

    странное заключение.... поясните пожалуйста.... 

    Пояснение в сообщении которое вы частично процитировали - читать сначала. Ссылки на issue и темы форумов приводить не буду, все вкладки уже позакрывал. Там что то связанное с Canvas и его реализацией в FMX...

  10. По результатам проб и тестов - не пытыйтесь использовать мой хелпер на длинных ListView или ListView содержимое которого может неожиданно изменится - нарветесь на AV. Я не нашел простого способа проверить существование самого себя и родителей.

    По Bitmap.LoadFromFile(ImagePath+Name) - загляните в исходники Эмбаркадеро, там все делается через TBitmapSurface :

    procedure TBitmap.LoadFromFile(const AFileName: string);
    var
      Surf: TBitmapSurface;
    begin
      TMonitor.Enter(Self);
      try
        Surf := TBitmapSurface.Create;
        try
          if TBitmapCodecManager.LoadFromFile(AFileName, Surf, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then
            Assign(Surf)
          else
            raise EBitmapLoadingFailed.CreateFMT(SBitmapLoadingFailedNamed, [AFileName]);
        finally
          Surf.Free;
        end;
      finally
        TMonitor.Exit(Self);
      end;
    end;

    Добавил к хелперу 

        procedure LoadFromFileAsync(const AFilePath : String; const ASize : TControlSize = nil); overload;
        procedure LoadFromFileAsync(const AFilePath : String; const AListItemImage : TListItemImage); overload;
        constructor CreateFromFileAsync(const AFilePath : String; const AListItemImage : TListItemImage = nil); overload;

    Сам хелпер и и архив с демо-проектом (загружает 1000 картинок в ListView, параллельно изменяя их размер, картинки в комплекте) :

    unit BitmapAsyncLoader;
    
    interface
    
    uses
      System.Net.HttpClient,
      System.Net.URLClient,
      System.SysUtils,
      System.Types,
      System.Classes,
      System.Threading,
      FMX.Graphics,
      FMX.Surfaces,
      FMX.Types,
      FMX.ListView.Types;
    
    type
      TBitmapAsyncLoader = class helper for TBitmap
      private
        function ResizeBitmapSurface(const ABitmapSurface : TBitmapSurface; const AWidth, AHeight : Integer) : TBitmapSurface;
        procedure SynchronizeAssignFromBitmapSurface(const ABitmapSurface : TBitmapSurface; const AListItemImage : TListItemImage = nil);
        procedure StartHTTPThread(const AURL : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil);
        procedure StartLoadFromFileThread(const AFilePath : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil);
      public
        procedure LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil); overload;
        procedure LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); overload;
        constructor CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil); overload;
    
        procedure LoadFromFileAsync(const AFilePath : String; const ASize : TControlSize = nil); overload;
        procedure LoadFromFileAsync(const AFilePath : String; const AListItemImage : TListItemImage); overload;
        constructor CreateFromFileAsync(const AFilePath : String; const AListItemImage : TListItemImage = nil); overload;
      end;
    
    implementation
    
    type
      THTTPClientListener = class
        class procedure HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean);
      end;
    
    var
      AHTTPClient : THTTPClient;
    
    procedure TBitmapAsyncLoader.LoadFromFileAsync(const AFilePath : String; const ASize : TControlSize = nil);
    var AWidth, AHeight : Integer;
    begin
      if Assigned(ASize) then
      begin
        AWidth:=Round(ASize.Width);
        AHeight:=Round(ASize.Height);
      end
      else
      begin
        AWidth:=-1;
        AHeight:=-1;
      end;
      StartLoadFromFileThread(AFilePath, AWidth, AHeight);
    end;
    
    procedure TBitmapAsyncLoader.LoadFromFileAsync(const AFilePath : String; const AListItemImage : TListItemImage);
    var AWidth, AHeight : Integer;
    begin
      if Assigned(AListItemImage) then
      begin
        AWidth:=Round(AListItemImage.Width);
        AHeight:=Round(AListItemImage.Height);
      end
      else
      begin
        AWidth:=-1;
        AHeight:=-1;
      end;
      StartLoadFromFileThread(AFilePath, AWidth, AHeight, AListItemImage);
    end;
    
    constructor TBitmapAsyncLoader.CreateFromFileAsync(const AFilePath : String; const AListItemImage : TListItemImage = nil);
    begin
      Create;
      LoadFromFileAsync(AFilePath, AListItemImage);
    end;
    
    constructor TBitmapAsyncLoader.CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil);
    begin
      Create;
      LoadFromURLAsync(AURL, AListItemImage);
    end;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage);
    var AWidth, AHeight : Integer;
    begin
      if Assigned(AListItemImage) then
      begin
        AWidth:=Round(AListItemImage.Width);
        AHeight:=Round(AListItemImage.Height);
      end
      else
      begin
        AWidth:=-1;
        AHeight:=-1;
      end;
      StartHTTPThread(AURL, AWidth, AHeight, AListItemImage);
    end;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil);
    var AWidth, AHeight : Integer;
    begin
      if Assigned(ASize) then
      begin
        AWidth:=Round(ASize.Width);
        AHeight:=Round(ASize.Height);
      end
      else
      begin
        AWidth:=-1;
        AHeight:=-1;
      end;
      StartHTTPThread(AURL, AWidth, AHeight);
    end;
    
    function TBitmapAsyncLoader.ResizeBitmapSurface(const ABitmapSurface : TBitmapSurface; const AWidth, AHeight : Integer) : TBitmapSurface;
    begin
      if (AWidth <> -1) and (AHeight <> -1) then
      begin
        try
          Result:=TBitmapSurface.Create;
          Result.StretchFrom(ABitmapSurface, AWidth, AHeight, ABitmapSurface.PixelFormat);
        finally
          ABitmapSurface.Free;
        end;
      end
      else
        Result:=ABitmapSurface;
    end;
    
    procedure TBitmapAsyncLoader.SynchronizeAssignFromBitmapSurface(const ABitmapSurface : TBitmapSurface; const AListItemImage : TListItemImage = nil);
    begin
      TThread.Synchronize(Nil,
        procedure
        begin
          Assign(ABitmapSurface);
          ABitmapSurface.Free;
          if Assigned(AListItemImage) then
            AListItemImage.Invalidate;
        end
      );
    end;
    
    procedure TBitmapAsyncLoader.StartHTTPThread(const AURL : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil);
    begin
        AHTTPClient.BeginGet(
          procedure (const ASyncResult: IAsyncResult)
          var
            AHTTPResponse : IHTTPResponse;
            ABitmapSurface : TBitmapSurface;
          begin
            if Not ASyncResult.IsCompleted then
              exit;
            try
              AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult);
            except
              exit;
            end;
            if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then
            begin
              ABitmapSurface:=TBitmapSurface.Create;
              if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then
              begin
                ABitmapSurface:=ResizeBitmapSurface(ABitmapSurface, AWidth, AHeight);
                SynchronizeAssignFromBitmapSurface(ABitmapSurface, AListItemImage);
              end;
            end;
          end,
          AURL
        );
    end;
    
    procedure TBitmapAsyncLoader.StartLoadFromFileThread(const AFilePath : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil);
    begin
      TTask.Run(
        procedure
        var
          ABitmapSurface : TBitmapSurface;
        begin
          ABitmapSurface:=TBitmapSurface.Create;
          if TBitmapCodecManager.LoadFromFile(AFilePath, ABitmapSurface, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then
          begin
            ABitmapSurface:=ResizeBitmapSurface(ABitmapSurface, AWidth, AHeight);
            SynchronizeAssignFromBitmapSurface(ABitmapSurface, AListItemImage);
          end;
        end
      );
    end;
    
    class procedure THTTPClientListener.HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean);
    begin
      Accepted:=True;
    end;
    
    initialization
    
    AHTTPClient:=THTTPClient.Create;
    AHTTPClient.OnValidateServerCertificate:=THTTPClientListener.HTTPClientValidateServerCertificate;
    
    finalization
    
    if Assigned(AHTTPClient) then
      AHTTPClient.DisposeOf;
    
    end.

     

    BitmapAsyncLoader.7z

  11. Окончательный вариант. Долго бился с изменением размера картинки внутри потока (к примеру что бы в ListView не грузить картинки больше чем нужно). Средствами TBitmap это оказалось сделать невозможно (именно в потоке), чтение форумов, issue Эмбаркадеро, привело к туманному выводу что проблема в архитектуре FMX.  В Токио, TBitmap стал потокобезопасным - это означает что никогда не пытайтесь использовать Bitmap в потоке, рано или поздно получите артефакты и глюки.

    Я решил проблему отказавшись от работы с TBitmap в потоке, и использовав для этого TBitmapSurface (загрузка из stream, изменение размеров).

    Что умеет хелпер:

    1. Загрузка картинки в Bitmap и подгонкой размера (размер можно и не менять - не передавайте параметр ASize)

    procedure LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil); overload;

    2. Загрузка картинки в TListItemImage ListView. После Окончания загрузки хелпер выполнит AListItemImage.Invalidate в основном потоке приложения для отрисовки картинки.

    procedure LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); overload;

    3. Создание картинки. Тоже самое что и предыдущие, но можно сэкономить строчку кода ABitmap:=TBitmap.Create ?

    constructor CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil);

    По картинкам в ListView - можете на свой страх и риск грузить 100500 картинок, но лучше использовать загрузку только для видимой части (+- еще сколько то итемов). Хелпер тупо грузит картинки и не обеспечивает механизм оптимальной загрузки.

    Протестировано на Windows и Android.

    Ответы на вопросы которые мне задавали:

    1. Почему не создавать отдельный поток для каждой картинки, в нем создавать THTTPClient и делать запрос - пробовал этот вариант, он медленнее на порядок, даже под виндой это чертовски медленно. AHTTPClient.BeginGet и так создает отдельный поток на каждый запрос.
    2. Почему AHTTPClient глобальный для юнита - в хелпере нельзя вводить свои переменные, а создавать AHTTPClient внутри функции не выйдет - он убьется до завершения потока. И текущий вариант быстрее.

    Код хелпера и архив с тестовым проектом:

    unit BitmapAsyncLoader;
    
    interface
    
    uses
      System.Net.HttpClient,
      System.Net.URLClient,
      System.SysUtils,
      System.Types,
      System.Classes,
      FMX.Graphics,
      FMX.Surfaces,
      FMX.Types,
      FMX.ListView.Types;
    
    type
      TBitmapAsyncLoader = class helper for TBitmap
      private
        function ResizeBitmapSurface(const ABitmapSurface : TBitmapSurface; const AWidth, AHeight : Integer) : TBitmapSurface;
        procedure SynchronizeAssignFromBitmapSurface(const ABitmapSurface : TBitmapSurface; const AListItemImage : TListItemImage = nil);
        procedure StartHTTPThread(const AURL : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil);
      public
        procedure LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil); overload;
        procedure LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); overload;
        constructor CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil);
      end;
    
    implementation
    
    type
      THTTPClientListener = class
        class procedure HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean);
      end;
    
    var
      AHTTPClient : THTTPClient;
    
    constructor TBitmapAsyncLoader.CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil);
    begin
      Create;
      LoadFromURLAsync(AURL, AListItemImage);
    end;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage);
    var AWidth, AHeight : Integer;
    begin
      if Assigned(AListItemImage) then
      begin
        AWidth:=Round(AListItemImage.Width);
        AHeight:=Round(AListItemImage.Height);
      end
      else
      begin
        AWidth:=-1;
        AHeight:=-1;
      end;
      StartHTTPThread(AURL, AWidth, AHeight, AListItemImage);
    end;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil);
    var AWidth, AHeight : Integer;
    begin
      if Assigned(ASize) then
      begin
        AWidth:=Round(ASize.Width);
        AHeight:=Round(ASize.Height);
      end
      else
      begin
        AWidth:=-1;
        AHeight:=-1;
      end;
      StartHTTPThread(AURL, AWidth, AHeight);
    end;
    
    function TBitmapAsyncLoader.ResizeBitmapSurface(const ABitmapSurface : TBitmapSurface; const AWidth, AHeight : Integer) : TBitmapSurface;
    begin
      if (AWidth <> -1) and (AHeight <> -1) then
      begin
        try
          Result:=TBitmapSurface.Create;
          Result.StretchFrom(ABitmapSurface, AWidth, AHeight, ABitmapSurface.PixelFormat);
        finally
          ABitmapSurface.Free;
        end;
      end
      else
        Result:=ABitmapSurface;
    end;
    
    procedure TBitmapAsyncLoader.SynchronizeAssignFromBitmapSurface(const ABitmapSurface : TBitmapSurface; const AListItemImage : TListItemImage = nil);
    begin
      TThread.Synchronize(Nil,
        procedure
        begin
          Assign(ABitmapSurface);
          ABitmapSurface.Free;
          if Assigned(AListItemImage) then
            AListItemImage.Invalidate;
        end
      );
    end;
    
    procedure TBitmapAsyncLoader.StartHTTPThread(const AURL : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil);
    begin
        AHTTPClient.BeginGet(
          procedure (const ASyncResult: IAsyncResult)
          var
            AHTTPResponse : IHTTPResponse;
            ABitmapSurface : TBitmapSurface;
          begin
            if Not ASyncResult.IsCompleted then
              exit;
            try
              AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult);
            except
              exit;
            end;
            if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then
            begin
              ABitmapSurface:=TBitmapSurface.Create;
              if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, Self.CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then
              begin
                ABitmapSurface:=ResizeBitmapSurface(ABitmapSurface, AWidth, AHeight);
                SynchronizeAssignFromBitmapSurface(ABitmapSurface, AListItemImage);
              end;
            end;
          end,
          AURL
        );
    end;
    
    class procedure THTTPClientListener.HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean);
    begin
      Accepted:=True;
    end;
    
    initialization
    
    AHTTPClient:=THTTPClient.Create;
    AHTTPClient.OnValidateServerCertificate:=THTTPClientListener.HTTPClientValidateServerCertificate;
    
    finalization
    
    if Assigned(AHTTPClient) then
      AHTTPClient.DisposeOf;
    
    end.

     

    BitmapAsyncLoader.7z

  12. В 17.07.2019 в 05:40, Ronalds Rizakovs сказал:

    Заработала с TakePhotoFromCameraAction. Только одна строчка кода для обработчика TakePhotoFromCameraAction1DidFinishTaking

    Такие официальные мануалы только мозг пудрит... 

    Здесь правлений мануал. http://docwiki.embarcadero.com/RADStudio/XE5/en/Mobile_Tutorial:_Taking_and_Sharing_a_Picture_(iOS_and_Android)

    И нужно установить Project Options > Entitlements List > Secure File Sharing в значение true.      (Этого тоже нету в мануале...) 

    Обратите внимание к какой версии документации вы обращаетесь:

    http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Taking_Pictures_Using_FireMonkey_Interfaces

    http://docwiki.embarcadero.com/RADStudio/XE5/en/Mobile_Tutorial:_Taking_and_Sharing_a_Picture_(iOS_and_Android)

    Актуальная документация для 10.3

    http://docwiki.embarcadero.com/RADStudio/Rio/en/Taking_Pictures_Using_FireMonkey_Interfaces

    Разрешение на доступ Secure File Sharing возможно не понадобится если уберете галочку:

    image.thumb.png.bee133d36dc7f457495aa5664199951f.png

  13. В 19.07.2019 в 12:47, Ronalds Rizakovs сказал:

    Rad studio 10.3

    Поискал по форуму, по гуглил. Но все старое. типа похоже, но не то. Непонятно где ключи взывать, окошки отличаютса.... 

    Простите новичка.... :( 

    http://docwiki.embarcadero.com/RADStudio/Rio/en/Firebase_Android_Support

  14. Пока тестировал хелпер в боевом проекте он потихоньку оброс исрпавлениями/улучшениями:

    1. Загрузка из потока сделана через TBitmapSurface - это позволяет избежать множества глюков.
    2. LoadFromStream вынесен из Synchronize (основного потока) в поток HTTPClient - по результатам бенчмарка операция оказалась самая жручая. После исправления интерфейс перестал залипать совсем.
    3. Добавлен overload вариант с передачей в процедуру TListItemImage - для использования в TListView и корректной перерисовки подгруженных картинок через AListItemImage.Invalidate.
    unit BitmapAsyncLoader;
    
    interface
    
    uses
      FMX.Graphics,
      FMX.Surfaces,
      System.Net.HttpClient,
      System.Types,
      System.Classes,
      FMX.ListView.Types,
      FMX.ListView.Appearances;
    
    type
      TBitmapAsyncLoader = class helper for TBitmap
        procedure LoadFromURLAsync(const AUrl : String); overload;
        procedure LoadFromURLAsync(const AUrl : String; const AListItemImage : TListItemImage); overload;
      end;
    
    implementation
    
    var
      AHTTPClient : THTTPClient;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String);
    begin
      try
        AHTTPClient.BeginGet(
          procedure (const ASyncResult: IAsyncResult)
          var
            AHTTPResponse : IHTTPResponse;
            ABitmapSurface : TBitmapSurface;
          begin
            if Not ASyncResult.IsCompleted then
              exit;
            try
              AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult);
            except
            end;
            if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then
            begin
              ABitmapSurface:=TBitmapSurface.Create;
              if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then
                TThread.Synchronize(Nil,
                  procedure
                  begin
                    if Assigned(Self)then
                      Assign(ABitmapSurface);
                    ABitmapSurface.Free;
                  end
                )
              else
                ABitmapSurface.Free;
            end;
          end,
          AURL
        );
      except
      end;
    end;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage);
    begin
      try
        AHTTPClient.BeginGet(
          procedure (const ASyncResult: IAsyncResult)
          var
            AHTTPResponse : IHTTPResponse;
            ABitmapSurface : TBitmapSurface;
          begin
            if Not ASyncResult.IsCompleted then
              exit;
            try
              AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult);
            except
            end;
            if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then
            begin
              ABitmapSurface:=TBitmapSurface.Create;
              if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then
                TThread.Synchronize(Nil,
                  procedure
                  begin
                    if Assigned(Self) and Assigned(AListItemImage) then
                    begin
                      AListItemImage.BeginUpdate;
                      Assign(ABitmapSurface);
                      AListItemImage.Invalidate;
                      AListItemImage.EndUpdate;
                    end;
                    ABitmapSurface.Free;
                  end
                )
              else
                ABitmapSurface.Free;
            end;
          end,
          AURL
        );
      except
      end;
    end;
    
    initialization
    
    AHTTPClient:=THTTPClient.Create;
    
    finalization
    
    if Assigned(AHTTPClient) then
      AHTTPClient.DisposeOf;
    
    end.

    Тестовый проект, на этот раз с ListView (по кнопке добавляется 100 итемов) прилагаю.

    BitmapAsyncLoaderListView.7z

  15. Для одного своего проекта сделал, поделюсь, вдруг кому пригодится. Тестировал под Windows и Android.

    Для использования просто добавьте BitmapAsyncLoader в uses, а дальше все просто:

    ImageControl.Bitmap.LoadFromURLAsync('https://bipbap.ru/wp-content/uploads/2017/10/0_8eb56_842bba74_XL-640x400.jpg');

    Код юнита хелпера:

    unit BitmapAsyncLoader;
    
    interface
    
    uses
      FMX.Graphics,
      System.Net.HttpClient,
      System.Types,
      System.Classes;
    
    type
      TBitmapAsyncLoader = class helper for TBitmap
        procedure LoadFromUrlAsync(const AUrl : String);
      end;
    
    implementation
    
    var
      AHTTPClient : THTTPClient;
    
    procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String);
    begin
      try
        AHTTPClient.BeginGet(
          procedure (const ASyncResult: IAsyncResult)
          var
            AHTTPResponse : IHTTPResponse;
          begin
            if Not ASyncResult.IsCompleted then
              exit;
            try
              AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult);
            except
            end;
            if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then
              TThread.Synchronize(Nil,
                procedure
                begin
                  try
                    Self.LoadFromStream(AHTTPResponse.ContentStream);
                  except
                  end;
                end
              );
          end,
          AURL
        );
      except
      end;
    end;
    
    initialization
    
    AHTTPClient:=THTTPClient.Create;
    
    finalization
    
    if Assigned(AHTTPClient) then
    begin
      AHTTPClient.DisposeOf;
    end;
    
    end.

    Архив с тестовым проектом прилагаю.

    BitmapAsyncLoader.7z

  16. 25 минут назад, Дмитрий Потапов сказал:

    В общем удалось решить проблему с кнопками пульта. Теперь приложение распознает все кнопки с пульта. Если кому-то нужно, прикрепил архив.

    fmx_androidkey_fix.zip 81 \u043a\u0411 · 0 downloads

    Спасибо! Посмотрел diff - как и предполагал, Эмбаркадера поленилась скопипастить все коды, видимо в буфер обмена у них влезла только часть ? Ну как так то?

    image.thumb.png.c3b0ea4f7f909a028e82b546638c3133.png

     

    Спасибо вам за проделанную работу!

  17. Одновременная работа Wifi и мобильной сети возможна. Но лично мне не удалось заставить их так работать )  Смысл в включении режима HIPRI.

    Вот код, может разберетесь почему не работает. Если удастся заставить работать, то напишите, будет интересно узнать где я ошибся.

    Если не получится, то вы можете отключать wifi на телефоне, отправлять данные по включившемуся мобильному интернету, и опять включать wifi.

    unit UnitFormMain;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
      Androidapi.Helpers,
      Androidapi.JNI.GraphicsContentViewText,
      Androidapi.JNI.JavaTypes,
      Androidapi.JNIBridge,
      Androidapi.JNI.Net, FMX.WebBrowser;
    
    type
      TFormMain = class(TForm)
        WebBrowser: TWebBrowser;
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
        function GetConnectivityManager: JConnectivityManager;
      public
        { Public declarations }
      end;
    
    var
      FormMain: TFormMain;
    
    implementation
    
    {$R *.fmx}
    
    procedure TFormMain.FormCreate(Sender: TObject);
    var
      ConnectivityManager : JConnectivityManager;
    begin
      ConnectivityManager:=GetConnectivityManager;
      ConnectivityManager.setNetworkPreference(TJConnectivityManager.JavaClass.TYPE_MOBILE);
      ConnectivityManager.startUsingNetworkFeature(TJConnectivityManager.JavaClass.TYPE_MOBILE, StringToJString('enableHIPRI'));
      Sleep(3000);
      if ConnectivityManager.getActiveNetworkInfo.isConnected then
        WebBrowser.Navigate('https://whoer.net/ru');
    end;
    
    function TFormMain.GetConnectivityManager: JConnectivityManager;
    var
      ConnectivityServiceNative: JObject;
    begin
      ConnectivityServiceNative := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.CONNECTIVITY_SERVICE);
      if not Assigned(ConnectivityServiceNative) then
        raise Exception.Create('Could not locate Connectivity Service');
      Result := TJConnectivityManager.Wrap(
        (ConnectivityServiceNative as ILocalObject).GetObjectID);
      if not Assigned(Result) then
        raise Exception.Create('Could not access Connectivity Manager');
    end;
    end.

    По поводу второго вопроса - с весами (терминалами и т.п.) проще работать в строчном режиме. Хотя на вкус и цвет...

    if FIdTCPClient.IOHandler.CheckForDataOnSource(FTimeouts.ReadTimeout) then
      ASendingData.Value:=FIdTCPClient.IOHandler.ReadLnWait;

     

  18. 1 час назад, Alex7wrt сказал:

    Получилось, но только с подключением дополнительных фреймворков. Использовал JVEsuite.

    Как и предполагал - я слишком тупой чтоб понять их инструкцию по установке.

    1. Go to Tools -> Options -> SDK Manager à iOS Device, for each iPhoneOS device:
    2. Click on any framework (just a click: there is a bug in IDE).
    3. Click “Add a new path item” image button (top one)
      1. Set “Path on remote machine” to “/System/Library/Frameworks” or “$(SDKROOT)/System/Library/Frameworks” (same as other frameworks).
      2. Set “Framework name” to “SystemConfiguration”.
      3. Click Ok (nothing should be selected in the radio and leave the checkbox unchecked).
    4. Repeat step 3 with Framework name “AdSupport”, “StoreKit”, “Social”, “CoreData”, “CoreTelephony”, “CoreMedia”, “SystemConfiguration”, “Security”, “EventKit”, “EventKitUI”, “AVFoundation”, “iAd”, “AudioToolbox”, “CoreBluetooth”, “SafariServices”, “CoreMotion”, “MediaPlayer”, “MobileCoreServices”, “CoreVideo”, “MessageUI”, “Metal”, “IOSurface”, “ImageIO”, “CoreAudio”, “MediaToolbox”, “CoreMIDI”, “JavaScriptCore”, “ModelIO” (no need to duplicate already existing items: Delphi XE5, for example, already includes StoreKit and iAd).
    5. Click “Update Local File Cache” button.

    В эти папки ($(SDKROOT)/System/Library/Frameworks/...) надо что то положить? Где взять все эти фреймворки? Или я туплю?

  19. 44 минуты назад, Alex7wrt сказал:

    Получилось, но только с подключением дополнительных фреймворков. Использовал JVEsuite.

    Хотя наверное куплю у них все за $100, там даже Google Analytics есть, Эмбаркадера это сделает наверное никогда.

    Вообще странно что Эмбаркадера кладет на такие важные вещи как монетизация приложений  - сделай пользователей своих продуктов богаче и тебе перепадет больше денег за подписки и прочее. Простая как 3 копейки идея, но маркетологи Эмбы видимо еще не дочитали учебник до этого места.

  20. 26 минут назад, Alex7wrt сказал:

    Получилось, но только с подключением дополнительных фреймворков. Использовал JVEsuite.

    Спасибо за ответ!

    Ads Support only pack for $70.00 ? Жаба конечно душит, но думаю окупится. 

    Какие то подводные камни обнаружились в компоненте или все норм? Почитал их инструкцию по установке (https://www.jvesoft.com/wp/configuring-ios/) нифига не понял, но вроде супер-сложного ничего нет.

  21. В 23.02.2017 в 13:04, Alex7wrt сказал:

    Наверно, вряд ли кто-то интегрировал AdMob в iOS, тогда интересует как правильно подключать iOS фреймворки и потом добавлять их в uses.

    Получилось у вас запустить AdMob в iOS? Сейчас в Rio пробую, без подключения дополнительных фреймворков, но объявление пустое всегда и ошибка "Не удалось завершить операцию. Запас рекламных объявлений исчерпан". Пробовал и в testmode и без него. В admob приложение и банер добавлены более суток назад.

     

  22. Подскажите, реально ли в текущий момент сделать рекламу в iOS приложениях? 

    Документация эмбаркадеры, вроде и современная (http://docwiki.embarcadero.com/RADStudio/Rio/en/Using_the_AdMob_Service в примеру), но пометка внизу страниц "This page was last edited on 28 September 2015, at 15:17." дает понять что они забили на этот раздел документации 4 года назад, и с выходом Rio тупо скопипастили, чтоб было. Издевательство какое то (

     

    P.S. В документации идет речь о iAd, но согласно Apple:

    About the iAd App Network Shutdown As of December 31, 2016, the iAd App Network is no longer available.

     

     

×
×
  • Создать...