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

PowerOwl

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

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

  • Посещение

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

    7

Сообщения, опубликованные PowerOwl

  1. 12 часов назад, Станислав Менинник сказал:

    Может кто знает, в 10.4 под Андроид появилось решение, что бы просто получать содержимое страницы как текст (длинный текст)?

    Решил эту задачу через одно место (сокеты), бывает подвисает приложуха, но хотелось бы напрямую, без костылей.

    Если я правильно понял, то

    ..
    uses System.Net.URLClient, System.Net.HttpClient, System.Net.HttpClientComponent;
    ..
    procedure Button1.Click(Sender:TObject);
    begin
    Memo1.lines.LoadFromStream(NetHTTPClient1.Get('http://yoursite.com/').ContentStream);
    end;  

     

  2. Здравствуйте! Хочу поделиться своим опытом в использовании класса android.app.DownloadManager из Android API.

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

    Возможности, предоставляемые классом:

    1.Скачивание любого файла из интернета с последующим сохранением

    2.Вывод уведомления о процессе загрузки с настраиваемым названием и описанием

    3.Разрешение загрузки только через конкретный вид сети, через роуминг, когда девайс заряжается и т.д.

    Вот ссылки на официальную документацию по классу DownloadManager и его подклассу DownloadManager.Request: https://developer.android.com/reference/android/app/DownloadManager

    https://developer.android.com/reference/android/app/DownloadManager.Request

    Демо-проект и обёртку для класса и прикрепил внизу.

    В примере по нажатию на кнопку происходит загрузка картинки в директорию /storage/emulated/0/Pictures

    -----------------------------------------------------------------------------

    Для начала, необходимо подключить библиотеки, необходимые приложению для работы:

    uses
      androidapi.JNI.JavaTypes, androidapi.Helpers,
      androidapi.JNI.GraphicsContentViewText,
      android.app.DownloadManager, androidapi.JNI.Net, System.Permissions, Androidapi.JNI.Os;

    Теперь нужно запросить у пользователя разрешение на запись в хранилище:

    procedure TForm1.FormCreate(Sender: TObject);
    var
      WRITE_EXTERNAL_STORAGE:String;
    begin
      WRITE_EXTERNAL_STORAGE:=JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
    
      PermissionsService.DefaultService.RequestPermissions([WRITE_EXTERNAL_STORAGE],
      procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
      begin
       if (Length(AGrantResults)=1) and (AGrantResults[0]=TPermissionStatus.Granted) then
       ShowMessage('Permission granted!')
       else
       begin
         Showmessage('Permission Denied! Manually go to "Settings-Applications-Project1-Permissions" and set Storage permission!');
         Application.Terminate;
       end;
      end )
    end;

    Если разрешение получено, то появится сообщение "Permission granted!", если нет, то программа попросит пользователя перейти в настройки и установить разрешение вручную.

    Отлично, разрешение получено, теперь можно написать и саму процедуру загрузки файла.

    procedure Download(code: string); //процедура будет получать уникальный код картинки на сайте pixabay.com
    var
      DownloadManager: JDownloadManager;          //Объект класса DownloadManager для загрузки файла
      DownloadRequest: JDownloadManager_Request;  //Объект класса DownloadManager_Request для установки настроек загрузки
      link: JString;                              //Переменная для хранения ссылки
      URI, URIPath: JNet_URI;         //В URI будем получать ссылку на картинку, в URIPath - путь к загруженной картинке в файловой системе 
      DownloadPermission: JObject;                //Объект для получения доступа к сервису загрузки
    begin
      link := StringToJString('https://pixabay.com/get/' + code + '_1280.jpg');  //получаем ссылку на картинку
    
      URI := TJNet_URI.JavaClass.parse(link);                                                                //заносим ссылку в URI
      URIPath := TJNet_URI.JavaClass.parse(StringToJString('file:///storage/emulated/0/Pictures/img.jpg'));  //заносим путь в URIPath
    
    
      DownloadRequest := TJDownloadManager_Request.JavaClass.init(URI);  //инициализируем DownloadRequest с ссылкой на файл
      DownloadRequest.setDestinationUri(URIPath);                        //Устанавливаем конечный путь в DownloadRequest 
    
      DownloadPermission := SharedActivityContext.getSystemService       //Получаем доступ к сервису загрузки
        (TJContext.JavaClass.DOWNLOAD_SERVICE);
    
      DownloadManager := TJDownloadManager.Wrap(DownloadPermission);     //Даём доступ к сервису загрузки DownloadManager'у
      DownloadManager.enqueue(DownloadRequest);                          //Запускаем загрузку
    end;

    Вот и всё, осталось только процедура нажатия на кнопку

    procedure TForm1.Button1Click(Sender: TObject);
    begin
     Download('g1e06713e4c5d9a9c5356f9e481ca8c37a7800ff986743fe4364aef699782e22b6a41f794dfd54ed32783eb0a577dc21b4dd2ba8fd83b6722740285291263d718');
    end;

    Теперь можно компилировать программу и проверить, работает-ли она. Если всё сработало, то в директории Pictures должен появиться файл "img.jpg", содержащий в себе изображение тюльпанов.

    Надеюсь, это Вам поможет, если у Вас будут проблемы с загрузкой файлов. Удачи в проектах!

    File Downloading.7z

  3. Оставлю тут код демо-проекта и обёртку для WallpaperManager, кому-нибудь в будущем пригодятся.

    // Подключить System.IOUtils, Androidapi.JNI.GraphicsContentViewText,
    //  Androidapi.JNI.JavaTypes,
    //  Androidapi.helpers, android.app.WallpaperManager; (android.app.WallpaperManager распаковать и закинуть к исходникам проекта)
    
    //перейти в Project->Options->Application->Uses permissions и поставить галочку напротив пункта "Set wallpaper"
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      path: string;
      str: JString;
      Wallpaper: JWallpaperManager;
      Image: JBitmap;
      Context: JContext;
    begin
      if Edit1.Text <> '' then
      begin
        path := Tpath.Combine(Tpath.GetDocumentsPath, Edit1.Text); //Вместо TPath.GetDocumentsPath можно написать путь к любой директории на  //устройстве, вместо Edit1.text - название картинки(с расширением, важно соблюдать регистр!!!)
        str := StringToJString(path);
        Context := SharedActivityContext;
        try
          if FileExists(path) then
          begin
            ShowMessage('Файл найден');
            Image := TJBitmapFactory.JavaClass.decodeFile(str)
          end
          else
            ShowMessage('Файл не найден');
        except
          ShowMessage('Не удалось декодировать');
        end;
        try
          Wallpaper := TJWallpaperManager.JavaClass.getInstance(Context);
          Wallpaper.setBitmap(Image);
        except
          ShowMessage('Не удалось установить обои');
        end;
      end;
    end;

     

    android.app.WallpaperManager.pas.7z

  4. Извиняюсь за потраченное время, я сам затупил... У меня клавиатура автоматически переключается в верхний регистр перед началом набора текста, и поэтому программа не могла найти файл. Забыл, что в C-подобных языках регистр имеет значение. В общем, программа работает.

    А что по поводу изучения основ, то я был бы рад их изучить, но не могу найти нигде нормальную(современную) литературу, где доходчиво объясняется использование библиотеки Firemonkey.

    P.S. Я ещё заметил, что у объектов класса JContext есть методы для работы с обоями, но в официальной документации Android сказано, что их вырезали в API Level 15, так что для программирования до Android 4.0 можно обойтись и без WallpaperManager

  5. 1 час назад, Andrey Efimov сказал:

    В эту директорию "/data/data/<application ID>/files"? (т.е. вы используете устройство с root правами?)

    Да, root на телефоне есть, но доступ к этой директории можно получить подключив телефон к компьютеру.

  6. Спасибо, понял. К сожалению, это опять-таки не исправило ошибку. В отладке я посмотрел, какие значения у объектов, и обнаружил, что у объекта Image значение nil. Тогда я посмотрел в Androidapi.JNI.GraphicsContentViewText.pas класс BitmapFactory, и там почему-то в разделе декларации методов объекта JBitmapFactory ничего нет. Возможно я ошибаюсь, но мне кажется, что так быть не должно.

     

    procedure TForm1.Button1Click(Sender: TObject);
    var
      path: string;
      str: JString;
      Wallpaper: JWallpaperManager;
      Image: JBitmap;
      Context: JContext;
    begin
      if Edit1.Text <> '' then
      begin
        path := Tpath.Combine(Tpath.GetDocumentsPath, Edit1.Text);
        str := StringToJString(path);
        Context:=SharedActivityContext;
        try
          Image := TJBitmapFactory.JavaClass.decodeFile(str);
        except
          ShowMessage('Не удалось декодировать');
        end;
        try
         Wallpaper:=TJWallpaperManager.JavaClass.getInstance(Context);
         Wallpaper.setBitmap(Image);
        except
          ShowMessage('Не удалось установить обои');
        end;
      end;
    end;

    356519003_29-06-202118-28-52.thumb.png.cd72f9251da604744ff9dc6e8137dd1d.png

  7. Спасибо за замечания, буду пытаться исправляться.

    1) Спасибо, перечитал, разобрался

    2) Приложу обёртку снизу

    3) Я не могу понять, где взять Context для этого метода. В Java-примерах для его получения используют функцию getContext(), но в Firemonkey такой нет.

    unit android.app.WallpaperManager;
    
    interface
    
    uses
      Androidapi.JNIBridge,
      Androidapi.JNI.GraphicsContentViewText,
      Androidapi.JNI.JavaTypes,
      Androidapi.JNI.Net,
      Androidapi.JNI.Os,
      Androidapi.JNI.Util;
    
    type
    // ===== Forward declarations =====
    
      JWallpaperInfo = interface;//android.app.WallpaperInfo
      JWallpaperManager = interface;//android.app.WallpaperManager
    
    // ===== Interface declarations =====
    
      JWallpaperInfoClass = interface(JObjectClass)
        ['{D1CC9CBB-D53F-4F29-ADA9-DD0BF04B0C86}']
        {class} function _GetCREATOR: JParcelable_Creator; cdecl;
        {class} function init(context: JContext; service: JResolveInfo): JWallpaperInfo; cdecl;
        {class} function describeContents: Integer; cdecl;
        {class} procedure dump(pw: JPrinter; prefix: JString); cdecl;
        {class} function getComponent: JComponentName; cdecl;
        {class} function getSettingsActivity: JString; cdecl;
        {class} function loadAuthor(pm: JPackageManager): JCharSequence; cdecl;
        {class} function loadDescription(pm: JPackageManager): JCharSequence; cdecl;
        {class} function toString: JString; cdecl;
        {class} procedure writeToParcel(dest: JParcel; flags: Integer); cdecl;
        {class} property CREATOR: JParcelable_Creator read _GetCREATOR;
      end;
    
      [JavaSignature('android/app/WallpaperInfo')]
      JWallpaperInfo = interface(JObject)
        ['{A357E89F-3891-4795-8207-B1416424D512}']
        function getPackageName: JString; cdecl;
        function getServiceInfo: JServiceInfo; cdecl;
        function getServiceName: JString; cdecl;
        function loadIcon(pm: JPackageManager): JDrawable; cdecl;
        function loadLabel(pm: JPackageManager): JCharSequence; cdecl;
        function loadThumbnail(pm: JPackageManager): JDrawable; cdecl;
      end;
      TJWallpaperInfo = class(TJavaGenericImport<JWallpaperInfoClass, JWallpaperInfo>) end;
    
      JWallpaperManagerClass = interface(JObjectClass)
        ['{F16EBFA1-4C27-4869-BEAA-3112EC3303A9}']
        {class} function _GetACTION_CHANGE_LIVE_WALLPAPER: JString; cdecl;
        {class} function _GetACTION_CROP_AND_SET_WALLPAPER: JString; cdecl;
        {class} function _GetACTION_LIVE_WALLPAPER_CHOOSER: JString; cdecl;
        {class} function _GetCOMMAND_DROP: JString; cdecl;
        {class} function _GetCOMMAND_SECONDARY_TAP: JString; cdecl;
        {class} function _GetCOMMAND_TAP: JString; cdecl;
        {class} function _GetEXTRA_LIVE_WALLPAPER_COMPONENT: JString; cdecl;
        {class} function _GetWALLPAPER_PREVIEW_META_DATA: JString; cdecl;
        {class} procedure clear; cdecl;//Deprecated
        {class} function getBuiltInDrawable(outWidth: Integer; outHeight: Integer; scaleToFit: Boolean; horizontalAlignment: Single; verticalAlignment: Single): JDrawable; cdecl; overload;
        {class} function getCropAndSetWallpaperIntent(imageUri: Jnet_Uri): JIntent; cdecl;
        {class} function getDesiredMinimumHeight: Integer; cdecl;
        {class} function getInstance(context: JContext): JWallpaperManager; cdecl;
        {class} function getWallpaperInfo: JWallpaperInfo; cdecl;
        {class} function hasResourceWallpaper(resid: Integer): Boolean; cdecl;
        {class} procedure sendWallpaperCommand(windowToken: JIBinder; action: JString; x: Integer; y: Integer; z: Integer; extras: JBundle); cdecl;
        {class} procedure setBitmap(bitmap: JBitmap); cdecl;
        {class} procedure setResource(resid: Integer); cdecl;
        {class} procedure setWallpaperOffsets(windowToken: JIBinder; xOffset: Single; yOffset: Single); cdecl;
        {class} procedure suggestDesiredDimensions(minimumWidth: Integer; minimumHeight: Integer); cdecl;
        {class} property ACTION_CHANGE_LIVE_WALLPAPER: JString read _GetACTION_CHANGE_LIVE_WALLPAPER;
        {class} property ACTION_CROP_AND_SET_WALLPAPER: JString read _GetACTION_CROP_AND_SET_WALLPAPER;
        {class} property ACTION_LIVE_WALLPAPER_CHOOSER: JString read _GetACTION_LIVE_WALLPAPER_CHOOSER;
        {class} property COMMAND_DROP: JString read _GetCOMMAND_DROP;
        {class} property COMMAND_SECONDARY_TAP: JString read _GetCOMMAND_SECONDARY_TAP;
        {class} property COMMAND_TAP: JString read _GetCOMMAND_TAP;
        {class} property EXTRA_LIVE_WALLPAPER_COMPONENT: JString read _GetEXTRA_LIVE_WALLPAPER_COMPONENT;
        {class} property WALLPAPER_PREVIEW_META_DATA: JString read _GetWALLPAPER_PREVIEW_META_DATA;
      end;
    
      [JavaSignature('android/app/WallpaperManager')]
      JWallpaperManager = interface(JObject)
        ['{A1B98FC3-5736-43BC-A41C-5588DC0D8838}']
        procedure clearWallpaperOffsets(windowToken: JIBinder); cdecl;
        procedure forgetLoadedWallpaper; cdecl;
        function getBuiltInDrawable: JDrawable; cdecl; overload;
        function getDesiredMinimumWidth: Integer; cdecl;
        function getDrawable: JDrawable; cdecl;
        function getFastDrawable: JDrawable; cdecl;
        function isWallpaperSupported: Boolean; cdecl;
        function peekDrawable: JDrawable; cdecl;
        function peekFastDrawable: JDrawable; cdecl;
        procedure setStream(data: JInputStream); cdecl;
    	procedure setBitmap(bitmap: JBitmap); cdecl;
        procedure setWallpaperOffsetSteps(xStep: Single; yStep: Single); cdecl;
      end;
      TJWallpaperManager = class(TJavaGenericImport<JWallpaperManagerClass, JWallpaperManager>) end;
    
    implementation
    
    procedure RegisterTypes;
    begin
      TRegTypes.RegisterType('android.app.WallpaperManager.JWallpaperInfo', TypeInfo(android.app.WallpaperManager.JWallpaperInfo));
      TRegTypes.RegisterType('android.app.WallpaperManager.JWallpaperManager', TypeInfo(android.app.WallpaperManager.JWallpaperManager));
    end;
    
    initialization
      RegisterTypes;
    end.
    
    

     

  8. 19 часов назад, Andrey Efimov сказал:

    Используйте вот такое обращение к этому методу

    Image := TJBitmapFactory.JavaClass.decodeFile(str);

     

    Попробовал использовать. Ошибка пропала, но появилась новая. Когда программа доходит до установки обоев, то появляется ошибка в файле Androidapi.JNIMarshall "Invoke error: Method not found", и обои сбрасываются на стандартные.

    Ещё нашёл статью, где рассказывается о использовании WallpaperManager: https://www.fmxexpress.com/code-snippet-to-set-the-device-wallpaper-in-delphi-xe7-firemonkey-on-android/ Попробовал использовать пример оттуда, пришлось его немного отредактировать, т.к. в нём были ошибки. Там используется полностью транслированное API, о котором Вы писали выше(в своём примере я использую файл, сгенерированный в Java2OP, и он использует только встроенные библиотеки). Также мне пришлось немного переписать android.graphics.BitmapFactory , потому что в качестве результатов некоторых функций там выступают JBitmap, и они путаются с классом JBitmap из встроенной библиотеки Androidapi.JNI.GraphicsContentViewText. Я изменил их на android.graphics.Bitmap.JBitmap. В общем, результат получился такой же: та же ошибка "Invoke error: Method not found". Код новой программы прикреплю.

    Код:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      path: string;
      str:JString;
      Image:JBitmap;
    begin
      if Edit1.Text <> '' then
      begin
        path := Tpath.Combine(Tpath.GetDocumentsPath, Edit1.Text);
        str:=StringToJString(path);
        try
        Image:=  TJBitmapFactory.JavaClass.decodeFile(str);
        except
         ShowMessage('Не удалось декодировать');
        end;
        try
        TJWallpaperManager.JavaClass.setBitmap(Image);
        except
         ShowMessage('Не удалось установить обои');
        end;
      end;
    end;

    ---------------------------------------------------

    Код новой программы:

    // подключить System.IOUtils, AndroidAPI.JNIBridge,
      AndroidAPI.JNI.JavaTypes,
      AndroidAPI.JNI.GraphicsContentViewText,
      AndroidAPI.JNI.os,
      AndroidAPI.helpers,
      android.app.WallpaperManager, android.graphics.Bitmap, android.graphics.BitmapFactory;
    
    procedure TForm1.Button1Click(Sender: TObject);
    Var
      FWallpaperManager: jwallpapermanager;
      Thebitmaptoshow:android.graphics.Bitmap.JBitmap;
      BitmapFact:android.graphics.BitmapFactory.TJBitmapFactory;
      Factoryoptions: JBitmapFactory_Options;
      FFiletoopen: String;
    begin
      { Create a filename to save the image to }
      FFiletoopen := System.IOUtils.TPath.Combine
        (System.IOUtils.TPath.getdocumentspath, Edit1.text);
      { Create  JBitmap options }
      Factoryoptions := TJBitmapFactory_Options.Create;
      { Read up on these in the android API }
      Factoryoptions.inJustDecodeBounds := true;
      Factoryoptions.inPreferQualityOverSpeed := true;
      Factoryoptions.inJustDecodeBounds := false;
      { Get the wallpaper manager instance }
      FWallpaperManager := tjwallpapermanager.Wrap
        ((SharedActivityContext.getSystemService
        (TJContext.JavaClass.WALLPAPER_SERVICE) as ILocalObject).GetObjectID);
      { Load the image we saved }
      TheBitmaptoShow := BitmapFact.JavaClass.decodeFile
        (StringToJString(FFiletoopen), Factoryoptions);
        { Set the Wallpaper }
        FWallpaperManager.setBitmap(TheBitmaptoShow);
    end;

     

  9. 23 часа назад, Andrey Efimov сказал:

    Для стандартного АПИ, в большинстве случаев, достаточно иметь только обёртку (.pas файл).

    Какая то часть обёрток для АПИ всегда идёт со студией в комплекте (найти можно тут: C:\Program Files (x86)\Embarcadero\Studio\версиястудии\source\).

    Если нужной вам обёртки нет в комплекте со студией, то либо генерите её самостоятельно, либо скачиваете с GitHub'а. На форуме есть упоминание об этом: Полностью транслированное Android API 7-23 уровня

    Для сторонних jar - библиотек, необходимо иметь саму библиотеку в виде jar файла и обёртку к ней.

     

    В вашем случае, должно хватить (если не брать во внимание callback OnColorsChangedListener) простого указания .pas файла в секции uses вашего приложения.

     

    p.s. Все начальные вопросы уже много раз обсуждались на форуме и в различных блогах, ищите, читайте, пробуйте :)

    p.s.2. Можете "покопаться", например, тут (https://delphifmandroid.blogspot.com/p/blog-page_27.html), тут (https://github.com/AndrewEfimov) и тут (http://yaroslavbrovin.ru/). Ну и конечно же, если вы хотите использовать специфичные функции Андроида, то необходимо ознакомиться https://developer.android.com

    Спасибо, написал небольшой пример. Всё компилируется, устанавливается, но при нажатии на кнопку показывается ошибка "Access violation at address 98CCCD32, accessing address 00000000", в RAD Studio показывается ошибка "Segmentation fault(11)" и указывается на строку с открытием картинки. Дал разрешение Set Wallpaper. Устройство Samsung Galaxy Note 4 SM-N910C, Android 6.0.1.

    Код:

    //Подключить System.IOUtils, Androidapi.JNIBridge,
      Androidapi.JNI.GraphicsContentViewText,
      Androidapi.JNI.JavaTypes,
      Androidapi.JNI.Net,
      Androidapi.JNI.Os,
      Androidapi.JNI.Util,
      Androidapi.helpers, Android.app.WallpaperManager;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      path: string;
      str:JString;
      Wallpaper: JWallpaperManagerClass;
      Image:JBitmap;
      BitmapFact:JBitmapFactoryClass;
    begin
      if Edit1.Text <> ' ' then
      begin
        path := Tpath.Combine(Tpath.GetDocumentsPath, Edit1.Text);
        str:=StringToJString(path);
        Image := BitmapFact.decodeFile(str);  //Тут ошибка
        try
        Wallpaper.setBitmap(Image);
        except
         ShowMessage('Не удалось установить обои');
        end;
      end;
    end;

     

  10. 5 часов назад, Andrey Efimov сказал:

    Посмотрите в сторону Android API: WallpaperManager, вероятно, с помощью этого апи можно менять обои.

     

    Подскажите, пожалуйста, как это чудо подключить к проекту. С помощью Java2OP создал bridge-файл, но не знаю, как его подключить. В справке Embarcadero сказано, что можно подключить через Project manager, но там нужен .jar файл, который я не знаю, откуда взять. Заранее спасибо, я ещё новичок в Firemonkey.

  11. Здравствуйте, у меня есть вопрос: можно-ли с помощью Firemonkey каким-либо образом сменить обои на рабочем столе Android? Я уже облазил весь интернет, нигде не смог найти ответа на свой вопрос. Использую Rad Studio 10.4.

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