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

Delphi 10.1 FMX android данные с сервера в base64 закодирован хранится pdf как его раскодировать и сохранить на устройстве


bossalex

Вопрос

Delphi 10.1 FMX android получаю данные с сервера в rest закодирован base64 хранится pdf, нужно его раскодировать и  сохранить на устройстве - далее отобразить пользователю

Пример ответа сервера:

{

  "code": 200,

  "body": {

    "finishFlag": true,

    "instanceId": "c9d0328a-6234-46d9-bc3b-d8adef9a0a71",

    "nextStep": {

      "pdf": "JVBERi0xL....PRg0K", -- pdf в base64 (он большой, для примера обрезал)

      "sort_order": 10,

      "is_not_prepr": false,

      "stepType": "A$FS_PRINT",

      "clientStep": true

    }

  },

Как отобразит вроде пример есть через intent (я это делал только через THttp скачивал и через установленный с плеймаркет просмотрщиком PDF просматривал  )

{$IFDEF ANDROID}
Uses
   Androidapi.JNI.GraphicsContentViewText,
   Androidapi.Helpers,
   Androidapi.JNI.JavaTypes,
   Androidapi.JNI.Net;
{$ENDIF}

procedure btnPdfClick(Sender: TObject);
var
   fName       : String;
{$IFDEF ANDROID}
   Intent      : JIntent;
   URI         : Jnet_Uri;
{$ENDIF}
begin
    fName := TPath.GetSharedDownloadsPath + PathDelim + 'test.pdf';

    {$IFDEF ANDROID}
      URI := TJnet_Uri.JavaClass.parse(StringToJString('file:///' + fName));
      intent := TJIntent.Create;
      intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
      intent.setDataAndType(URI,StringToJString('application/pdf'));
      SharedActivity.startActivity(intent);
    {$ENDIF}
end;

 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

А в чем загвоздка?
Достать поле из JSON - вроде просто, обычная работа с JSON далеко не самой сложной структуры.
Раскодировать из Base64 - uses System.NetEncoding; TNetEncoding.Base64.DecodeStringToBytes и сохранить их в файл
Потом открыть файл через интент.

Ссылка на комментарий
  • 2

Накидал вам функцию (проверил - работает):

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  System.JSON,
  System.NetEncoding,
  System.IOUtils;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    function ExtractPDFContentBase64(const AJSONString : String; out AFileName : String) : boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

function TForm1.ExtractPDFContentBase64(const AJSONString : String; out AFileName : String) : boolean;
Var AJSONObject, AJSONObjectBody, AJSONObjectNextStep : TJSONObject;
    ACode : Integer;
    AStreamSource, AStreamDest : TMemoryStream;
    ADecodeByteCount : Integer;
    ABase64 : String;
begin
  // Выставляем результат функции в False
  Result:=False;

  // Парсим JSON строку в JSON объект
  AJSONObject:=TJSONObject(TJSONObject.ParseJSONValue(AJSONString));
  if Not Assigned(AJSONObject) then
    exit;

  // Проверям поле code на предмет содержания http code 200 (это я домыслил, можно удалить)
  if Not AJSONObject.TryGetValue('code', ACode) then
    exit;
  if ACode <> 200 then
    exit;

  // Извлекаем body
  if Not AJSONObject.TryGetValue('body', AJSONObjectBody) then
    exit;
  if Not Assigned(AJSONObjectBody) then
    exit;

  // Из body извлекаем instanceId - будем использовать как имя файла
  if Not AJSONObjectBody.TryGetValue('instanceId', AFileName) then
    exit;
  // Склеиваем полное имя файла
//  AFileName:=TPath.Combine(TPath.GetSharedDownloadsPath, AFileName + '.pdf');
  AFileName:=TPath.Combine(TPath.GetSharedDownloadsPath, AFileName + '.jpeg'); // Я тестил на картинке

  // Извлекаем nextStep
  if Not AJSONObjectBody.TryGetValue('nextStep', AJSONObjectNextStep) then
    exit;
  if Not Assigned(AJSONObjectNextStep) then
    exit;

  // Содаем поток-источник и помещаем в него base64
  AStreamSource:=TMemoryStream.Create;
  if Not AJSONObjectNextStep.TryGetValue('pdf', ABase64) then
    exit;
  AStreamSource.WriteBuffer(Pointer(ABase64)^, Length(ABase64) * 2); // Длину строки умножаем на 2, так как строка юникод
  AStreamSource.Position:=0;

  // Создаем поток-назначение
  AStreamDest:=TMemoryStream.Create;
  // Декодируем base64 из текста в потоке AStreamSource в бинарные данные в поток AStreamDest
  ADecodeByteCount:=TNetEncoding.Base64.Decode(AStreamSource, AStreamDest);
  // Проверяем сколько байт было декодировано
  if (ADecodeByteCount > 0) then
  begin
    AStreamDest.Position:=0;
    try
      // Сохраняем поток с бинарными данными в файл с ранее собранным именем
      AStreamDest.SaveToFile(AFileName);
    except
      exit;
    end;
  end;
  // Выставляем результат функции в True
  Result:=True;
end;

procedure TForm1.FormCreate(Sender: TObject);
Var AJSONString : String;
    AFileName : String;
begin
  AJSONString:=TFile.ReadAllText('d:\JSON_example.txt');
  if ExtractPDFContentBase64(AJSONString, AFileName) then
  begin
    // Что то делаем с PDF файлом AFileName
  end;
end;

end.

 

Ссылка на комментарий
  • 1

1. для упрощения кода работы с JSON давно можно использовать сложные пути
ABase64:=JSON.GetValue<string>('body.nextStep.pdf');
2.  ну нельзя так: 

AStreamSource.WriteBuffer(Pointer(ABase64)^, Length(ABase64) * 2);

так безопасней AStreamSource:=TBytesStream.Create(TEncoding.UTF8.GetBytes(ABase64));

3. И сохранять лучше сразу в TFileStream - меньше расход памяти 

4. не забываем finally Free (их выше нету)... хоть оно и может AUTOREFCOUNT (а может и нет!), но правила хорошего тона никто не отменял

Изменено пользователем Slym
Ссылка на комментарий
  • 0
5 часов назад, Slym сказал:

1. для упрощения кода работы с JSON давно можно использовать сложные пути
ABase64:=JSON.GetValue<string>('body.nextStep.pdf');
2.  ну нельзя так: 


AStreamSource.WriteBuffer(Pointer(ABase64)^, Length(ABase64) * 2);

так безопасней AStreamSource:=TBytesStream.Create(TEncoding.UTF8.GetBytes(ABase64));

3. И сохранять лучше сразу в TFileStream - меньше расход памяти 

4. не забываем finally Free (их выше нету)... хоть оно и может AUTOREFCOUNT (а может и нет!), но правила хорошего тона никто не отменял

По пункту 1 :

Из за того что код парсинга JSON сотрудники Эмабаркадеро делали "по быстрому" (просто переделали ранее написаный код парсинга XML), то там присутствуют ошибки и конструкция

ABase64:=JSON.GetValue<string>('body.nextStep.pdf');

будет работать, но только при убывающей луне и на южном склоне холма ?

Исправили проблему только в Carnival.

По пункту 2 :

Согласен полностью.

По пункту 3:

Согласен полностью.

По пункту 4 :

Согласен, но я показывал как топикстартеру как выполнить его задачу, а не писал учебник по идеальному программированию ? Да и компилятор все равно вставляет код очистки локальных переменных при выходе из функции, так что будем считать что я просто снизил нагрузку на процессор ?

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...