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

Major

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

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

  • Посещение

Активность репутации

  1. Like
    Major получил реакцию от Brovin Yaroslav в Реестр в Андроиде и Delphi   
    ENRGY,
    а как вам такой способ (не мой)?
     
    uses Androidapi.Helpers, Androidapi.JNI.App, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText; var SP: JSharedPreferences; SPE: JSharedPreferences_Editor; procedure TMain.FormShow(Sender: TObject); begin SP := TAndroidHelper.Activity.getSharedPreferences(StringToJString('ZTApp'), 0); IP.Text := JStringToString(SP.getString(StringToJString('IP'), StringToJString('127.0.0.1'))); end; procedure TMain.SaveClick(Sender: TObject); begin SPE := SP.edit; SPE.putString(StringToJString('IP'), StringToJString(IP.Text)); SPE.commit; end;  
  2. Like
    Major отреагировална krapotkin в Зачем создается дополнительный файл формы   
    это не случайные символы. и создаете вы его сами, когда НАСЛЕДУЕТЕ master-форму для конкретных платформ и разрешений
    http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Using_FireMonkey_Views
  3. Like
    Major отреагировална Равиль Зарипов (ZuBy) в [Android] Доступ из программы к папкам res\   
    TAndroidHelper.Context.getResources().getIdentifier( StringToJString('название картинки без расширения'), StringToJString('drawable'), TAndroidHelper.Context.getPackageName); Чтобы картинки отображались согласно скейлу девайса, нужно чтобы они были во всех вариациях
    ldpi; mdpi; hdpi; xhdpi и тд... Ну и деплоить их правильно!
  4. Like
    Major отреагировална Евгений Корепов в Пример с TInAppPurchase   
    Хм. Можно и так это рассматривать. Но лучше сначала изучить теоретическую часть покупок в приложении и понять что именно и для чего вы делаете. Копипастить код не поможет. Подробности тут https://www.google.ru/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=покупки+в+приложениях+андроид&*
  5. Like
    Major отреагировална Евгений Корепов в Пример с TInAppPurchase   
    Вот мой юнит для работы с покупками в приложении:
    unit UnitInAppPurchase; interface uses // UnitGetDeviceInfo, FMX.InAppPurchase, System.Classes, System.SysUtils, System.Hash; //const // HashMixer = 'p345mcq34mq'; type TBillingEventPurchased = procedure(ASecretKey : String) of object; TBillingEventNotPurchased = procedure of object; TBillingLog = procedure(AMessage : String) of object; TBilling = class private InAppPurchase: TInAppPurchase; FBillingEventPurchased : TBillingEventPurchased; FBillingEventNotPurchased : TBillingEventNotPurchased; FBillingLog : TBillingLog; FNoAdsID : String; FSecretKey : String; FApplicationLicenseKey : String; procedure InAppPurchaseSetupComplete(Sender: TObject); procedure InAppPurchaseProductsRequestResponse(Sender: TObject; const Products: TIAPProductList; const InvalidProductIDs: TStrings); procedure InAppPurchaseError(Sender: TObject; FailureKind: TFailureKind; const ErrorMessage: string); procedure InAppPurchasePurchaseCompleted(Sender: TObject; const ProductID: string; NewTransaction: Boolean); procedure ConsumeComplete(Sender: TObject; const ProductID: string); procedure ConsumeFailed(Sender: TObject; const ProductID, ErrorMessage: string); function GetSecretKey : String; function CheckSecretKey : Boolean; procedure LogMy(AMessage : String); public // Constructor Create(AApplicationLicenseKey, ANoAdsID, ASecretKey : String); constructor Create(AApplicationLicenseKey, ANoAdsID : String); destructor Destroy; procedure CheckPurchase; procedure Purchase; // published property OnPurchased : TBillingEventPurchased read FBillingEventPurchased write FBillingEventPurchased; property OnNotPurchased : TBillingEventNotPurchased read FBillingEventNotPurchased write FBillingEventNotPurchased; property OnPurchasedError : TBillingEventNotPurchased read FBillingEventNotPurchased write FBillingEventNotPurchased; property OnLog : TBillingLog read FBillingLog write FBillingLog; end; implementation //Constructor TBilling.Create(AApplicationLicenseKey, ANoAdsID, ASecretKey : String); Constructor TBilling.Create(AApplicationLicenseKey, ANoAdsID : String); begin FNoAdsID:=ANoAdsID; FApplicationLicenseKey:=AApplicationLicenseKey; // FSecretKey:=ASecretKey; InAppPurchase:=TInAppPurchase.Create(Nil); InAppPurchase.ApplicationLicenseKey:=FApplicationLicenseKey; InAppPurchase.ProductIDs.Add(FNoAdsID); InAppPurchase.OnSetupComplete := InAppPurchaseSetupComplete; InAppPurchase.OnProductsRequestResponse := InAppPurchaseProductsRequestResponse; InAppPurchase.OnError := InAppPurchaseError; InAppPurchase.OnPurchaseCompleted := InAppPurchasePurchaseCompleted; InAppPurchase.OnConsumeCompleted := ConsumeComplete; InAppPurchase.OnConsumeFailed := ConsumeFailed; end; Destructor TBilling.Destroy; begin if Assigned(InAppPurchase) then FreeAndNil(InAppPurchase); inherited; end; procedure TBilling.Purchase; begin try InAppPurchase.PurchaseProduct(FNoAdsID); except LogMy('PurchaseProduct except'); end; end; procedure TBilling.CheckPurchase; begin if CheckSecretKey Then begin LogMy('CheckSecretKey True - Disable Ads'); FSecretKey:=GetSecretKey; if Assigned(OnPurchased) then OnPurchased(FSecretKey); Exit; end; LogMy('CheckSecretKey False - Check InAppPurchase status'); InAppPurchase.SetupInAppPurchase; end; function TBilling.GetSecretKey : String; Var ADeviceIMEI : String; begin // Это был костыль для хранения флага о покупке локально, не оправдал себя и изъят из обращения // ADeviceIMEI:=GetDeviceIMEI; // Result:=System.Hash.THashSHA1.GetHashString(HashMixer+ADeviceIMEI+FNoAdsID); end; function TBilling.CheckSecretKey : Boolean; begin Result:=False; // Result:=FSecretKey.Equals(GetSecretKey); end; procedure TBilling.InAppPurchaseSetupComplete(Sender: TObject); begin LogMy('InAppPurchaseSetupComplete'); try LogMy('InAppPurchase.QueryProducts'); InAppPurchase.QueryProducts; except on E:Exception do LogMy('QueryProducts Exception: '+e.Message); end; end; procedure TBilling.InAppPurchaseProductsRequestResponse(Sender: TObject; const Products: TIAPProductList; const InvalidProductIDs: TStrings); var Product: TProduct; begin LogMy('TMainForm.InAppPurchaseProductsRequestResponse'); LogMy('Start search '+FNoAdsId); LogMy('Products.Count='+Products.Count.ToString); for Product in Products do begin LogMy('Start search '+FNoAdsId); if Product.ProductID = FNoAdsId then begin LogMy('Founded '+FNoAdsId); if InAppPurchase.IsProductPurchased(FNoAdsId) then begin // КУПЛЕНО!!!! LogMy(FNoAdsID+' Yes ProductPurchased'); FSecretKey:=GetSecretKey; if Assigned(OnPurchased) then OnPurchased(FSecretKey); end Else begin LogMy(FNoAdsID+' Not ProductPurchased'); if Assigned(OnNotPurchased) then OnNotPurchased; end; Exit; end; end; LogMy('Product not found - OnNotPurchased'); if Assigned(OnNotPurchased) then OnNotPurchased; LogMy('TMainForm.InAppPurchaseProductsRequestResponse END'); end; procedure TBilling.InAppPurchaseError(Sender: TObject; FailureKind: TFailureKind; const ErrorMessage: string); Var S: String; begin if FailureKind = TFailureKind.ProductsRequest Then S:='ProductsRequest'; if FailureKind = TFailureKind.Purchase Then S:='Purchase'; if Assigned(OnPurchasedError) then OnPurchasedError; LogMy('Purchasing error ('+S+'):'+ErrorMessage); end; procedure TBilling.InAppPurchasePurchaseCompleted(Sender: TObject; const ProductID: string; NewTransaction: Boolean); begin LogMy('TMainForm.InAppPurchasePurchaseCompleted'); if ProductID = FNoAdsID then begin LogMy('HideAndDestroyAds'); FSecretKey:=GetSecretKey; if Assigned(OnPurchased) then OnPurchased(FSecretKey); end; end; procedure TBilling.ConsumeComplete(Sender: TObject; const ProductID: string); begin LogMy('Consume Complete: ' + ProductID); end; procedure TBilling.ConsumeFailed(Sender: TObject; const ProductID, ErrorMessage: string); begin LogMy('Consume Failed: ' + ProductID); end; procedure TBilling.LogMy(AMessage : String); begin if Assigned(OnLog) then OnLog(AMessage); end; end. Использовать вот так:
    const NoAdsID = 'mysuperapp_remove_ad'; //название товара, тоже что и консоли разработчика ... private Billing : TBilling; procedure BillingEventPurchased(ASecretKey : String); procedure BillingEventNotPurchased; procedure BillingEventPurchasedError; procedure BillingLog(AMessage : String); procedure DisablePurchaseUI; procedure EnablePurchaseUI; ... FormCreate start Var AppLicenseKey : String; ... AppLicenseKey:='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxim8ZGAIhK/FPhpXT0r6MXHYxYi1qcMfIiKOkiBDHcRYgRLK7'; AppLicenseKey:=AppLicenseKey+'********************************************************************************'; AppLicenseKey:=AppLicenseKey+'******************************************************************************'; AppLicenseKey:=AppLicenseKey+'*******************************************************************************'; AppLicenseKey:=AppLicenseKey+'Mgv7JP8A+qcDV3lm4M9OKBgxBRLaejxHd1iH3tsMR8PLkKUUf3yrMW8QIDAQAB'; Billing:=TBilling.Create(AppLicenseKey, NoAdsID); Billing.OnPurchased:=BillingEventPurchased; Billing.OnNotPurchased:=BillingEventNotPurchased; Billing.OnPurchasedError:=BillingEventPurchasedError; Billing.OnLog:=BillingLog; Billing.CheckPurchase; FormCreate stop ... procedure TFormMain.BillingEventPurchased(ASecretKey : String); begin // LogMy('CheckSecretKey True - Disable Ads'); Setting.Flags.AdsShowFlag:=False; DisablePurchaseUI; // удаляет кнопки и прочую фигню предлагающую купить товар (товар в данном случае - Удаление рекламы) HideAndDestroyAds; // удаление рекламы из приложения, так как товар куплен // Setting.SecretKey:=ASecretKey; // SaveFormState; end; procedure TFormMain.BillingEventNotPurchased; begin Setting.Flags.AdsShowFlag:=True; EnablePurchaseUI; ShowAds; end; procedure TFormMain.BillingEventPurchasedError; begin Setting.Flags.AdsShowFlag:=True; // EnablePurchaseUI; ShowAds; end; procedure TFormMain.BillingLog(AMessage : String); begin // Memo.Lines.Insert(0,AMessage); end; procedure TFormMain.DisablePurchaseUI; begin ButtonRemoveAds.Visible:=False; LayoutRemoveAds.Visible:=False; end; procedure TFormMain.EnablePurchaseUI; begin LayoutRemoveAds.Visible:=True; ButtonRemoveAds.Visible:=True; end;  
  6. Like
    Major отреагировална ENERGY в [Android] Работоспособность приложения на разных девайсах   
    На всех Android версиях от 4.0.4 до 7. На процессорах ARMv7. Также работает на Intel (Atom) процессорах через эмулятор ARM который разрабатывает Intel - libhoudini  обычно уже сразу установлен в таких девайсах.
    Также работает на процессорах  ARMv8 (x64) т.к. они поддерживают  инструкции ARMv7.
    По факту это наибольший сегмент мобильных устройств. Втч это Android Wear, Google Glass, разные Smart TV, Amazon FireTV, Amazon FirePhone, BlackBerry, см. статью.
    Не работает на ARMv6 и ниже довольный старый сегмент девайсов, ~2010, там и Android второй версии. Aндроид меньше 4 используют около ~1% девайсов сейчас (статистика).
     
    http://docwiki.embarcadero.com/PlatformStatus/en/Main_Page
    http://docwiki.embarcadero.com/RADStudio/Berlin/en/Android_Devices_Supported_for_Application_Development
    Интересная статья: 
    https://community.embarcadero.com/blogs?view=entry&id=8520
  7. Like
    Major отреагировална Alex7wrt в [Статья][AdMob] Добавляем рекламный блок в приложение   
    http://www.tahribat.com/forum/android---delphi-xe7-firemonkey-admob-interstitial-204528
  8. Like
    Major отреагировална ENERGY в OnShow для фрейма (Android)   
    OnResize .
    Но проверяйте что уже установили нужные размеры контролов\картинок, т.к. OnResize может выполняться многократно (если у первого компонента уже стоит нужная ширина then exit).
  9. Like
    Major получил реакцию от denprox в TCombobox и TextSettings   
    Здравствуйте!
    Почему у компонента TCombobox нет свойства TextSettings в инспекторе объектов? Зачем оно скрыто?
  10. Like
    Major отреагировална Error в Trackbar с отсечками   
    В моей статье есть решение: https://habrahabr.ru/post/317814/
  11. Like
    Major отреагировална Равиль Зарипов (ZuBy) в Зависает программа, использующая фреймы (Android)   
    Метод Release как раз нужно использовать когда удаляешь "сам из себя"
    На пальцах это выглядит так:
    при вызове метода Release объект помещается в список/очередь запускается таймер с интервалом 10 мсек, в котором идёт очистка этой очереди при очистке используется метод DisposeOf Не нужно везде использовать этот метод, только при крайней необходимости
  12. Like
    Major отреагировална kami в Зависает программа, использующая фреймы (Android)   
    if (TabControl1.ActiveTab = TabItem1) then if (FFrame <> nil) then begin FFrame.Parent := nil; FFrame.DisposeOf; FFrame := nil; end; вместо этого написать:
     
    if (TabControl1.ActiveTab = TabItem1) then if Assigned(FFrame) then begin FFrame.Release; FFrame := nil; end; Этого будет достаточно, чтобы завершились все обработчики событий и в то же время не было новых обращений к этому фрейму.
     
    Кстати, вам уже рекомендовалось использовать именно Release. Но, видимо, вам нравятся кактусы.
  13. Like
    Major отреагировална enatechno в Зависает программа, использующая фреймы (Android)   
    1 Вариант. Заменой удаления фреймов на скрытие (подправленный проект приложил).
    2 Вариант. Расположить панель с кнопкой Back на главной форме, а не дублировать ее в каждом фрейме. (При необходимости саму кнопку Back можно скрывать при возврате на первый таб).
    3 Вариант. Использовать отложенное удаление фрейма).
     ...
    и еще много разных вариантов.
    Click; FPressed := False; StartTriggerAnimation(Self, 'Pressed') Отладчик выдал ошибку в методе объекта TControl (в Вашем случае это кнопка SpeedButton1 на фрейме). В этом методе в Click вы удаляете Frame, а значит и кнопку на ней. А в строке StartTriggerAnimation(Self, 'Pressed'); вы обращаетесь к этой удаленной кнопке (Self). Здесь и происходит AV.
    test2.zip
  14. Like
    Major отреагировална enatechno в Зависает программа, использующая фреймы (Android)   
    1). Я так понимаю эта строка в модуле фрейма? Похоже на циклическую ссылку. Uses в модуле фрейма ссылается на Form1, а Form1 ссылается на модуль фрейма?
    2). Вы создаете фрейм каждый раз при открытии TabItem2? Много ли контролов на фрейме? Создание фрейма с контролами в рантайм на андроиде - затратная по времени операция. Если программа использует не много фреймов, то я бы не создавал/удалял каждый раз фрейм при смене таба, а использовал фрейм созданный один раз. Это улучшит отзывчивость программы.

    Ну а причина зависания - то, что вы в процедуре обработчика кнопки фрейма OnClick вызываете TForm1.TabControl1Change и там удаляете этот фрейм и саму кнопку.
  15. Like
    Major получил реакцию от Rusland в Что лучше: зашивать в ресурсы или Deployment? (Android)   
    я вот сейчас еще раз проверил. Всё, что кидалось в Deployment,  - в apk-файле находится в папке assets. А то, что подключалось через ресурсы (brcc32), то находится в .so-файле.
    Delphi 10.1 Berlin.
    Можете сами проверить
  16. Like
    Major отреагировална enatechno в OnCreate для фрейма   
    Да. 
    constructor Create(AOwner: TComponent); override;  
  17. Like
    Major отреагировална Andrey Efimov в [Статья][Android] Автоматическая смена названия приложения в зависимости от языка системы   
    Ссылка: http://delphifmandroid.blogspot.ru/2016/04/blog-post.html
    Автор: Андрей Ефимов
    Описание: Автоматическая смена названия приложения в зависимости от языка системы
  18. Like
    Major отреагировална Andrey Efimov в Version Info, label (Android)   
    Прямая ссылка в блог: Автоматическая смена названия приложения в зависимости от языка системы
    Ссылка на форуме(Раздел "Статьи"): [Статья][Android] Автоматическая смена названия приложения в зависимости от языка системы
    и ещё есть обычные темы по этому вопросу, но прикладывать не буду.
     
    p.s. Народ совсем обленился, сложно поиском воспользоваться...
  19. Like
    Major отреагировална rareMax в Текст с картинками и скроллингом   
    А делфи мучать обязательно? Сохрани word как pdf'ку и открывай на телефоне
  20. Like
    Major отреагировална enatechno в Прозрачные контролы   
    Это решается редактированием стиля. 
    Например так:
    1). Размещаете TGroupbox на форме
    2). ПКМ на нем
    3). в контекстном меню выбираете Edit Custom Style (или Edit Default style)
    4). в открывшемся редакторе стиля указываете платформу (Android)
    5). выбираете объект background (по умолчанию он белый).
    6). задаете ему свойство Visible=false
  21. Like
    Major отреагировална Равиль Зарипов (ZuBy) в Прозрачные контролы   
    в FMX все делается с помощью стилей, нужно отредактировать стиль TGroupbox
  22. Like
    Major отреагировална RoschinSpb в vkHardwareBack, vkHome, vkMenu (Android)   
    Средствами Fire Monkey нельзя. И это относится не только к HardwareBack, Home, Menu но и вообще к любым клавишам на любой клавиатуре. Возможно можно как-то воспользоваться андроидными системными функциями, но например в Windows нету системных средств для определения наличия физических клавиш. Так что обработка горячих клавиш всегда должна дублироваться какими-то другими интерфейсными элементами, если конечно Вы не хотите намеренно скрыть что-то от обычных пользователей.
  23. Like
    Major отреагировална ENERGY в Реестр в Андроиде и Delphi   
    SharedPreference удаляются при деинсталяции программы. 
  24. Like
    Major отреагировална ENERGY в Реестр в Андроиде и Delphi   
    В Unix нет реестра, там все на файлах.  Android, MacOS и iOS - это Unix. 
    В Android есть 2 варианта для сохранения данных, которые не будут удалены после деинсталяции - сохранять на SD карту, и сохранять удаленно в свою базу (через интернет). 
    http://stackoverflow.com/questions/19683614/android-persist-data-after-uninstall
    Хотя можно попробовать записать что-то и во внутреннее хранилище, в папки Music, Ringtones итп  почитайте здесь статью Saving files that can be shared with other apps
     
     
  25. Like
    Major отреагировална ENERGY в Утечка при использовании анонимного метода или анонимные методы, циклические ссылки и ARC   
    Это касается ARC компиляторов, Android, iOS и будущего Linux.
    Если контейнер владелец, содержит классы, которые используют анонимный метод для общения с ним (классом владельцем), то такая конструкция порождает утечку памяти из-за появления циклической ссылки. Т.к. при присваивании анонимного метода инкрементируется счетчик ссылок и не меняется. Причем это не указано в хелпе.

    А дело было так - при вызове MyCore.Free класс не уничтожался - не вызывался деструктор из за того, что после вызова Free, счетчик ссылок (reference Count) был равен 1. Приходилось пользоваться  DisposeOf. Решил разобраться.
    Для этого перекрыл виртуальные методы TObject отвечающие за изменения счетчика объекта (см. также полный пример ниже).
    function __ObjAddRef: Integer; override;
    function __ObjRelease: Integer; override;
     
    Итак TCore содержит класс TTestClass - у которого есть событие OnMyEvent. 
    Прототип описан как анонимная процедура - TAnonymProc = reference to procedure;

    При указании анонимной процедуры, т.е. : 
    procedure TCore.SetEvent; begin   fTest.OnMyEvent := procedure ()   begin     fSetFlag := true;   end; end; счетчик ссылок TCore увеличивается на 1 и не изменяется при выходе из SetEvent.
    Теперь при вызове Free TCore - не будет вызван деструктор, который должен уничтожит классы TCore и TTestClass и произойдет утечка памяти.

    Решение : 
    1. Использовать слабые ссылки - weak, в нашем примере добавить атрибут [weak]:
    TTestClass = class strict private   [weak]fOnMyEvent:TAnonymProc; public   property OnMyEvent: TAnonymProc read fOnMyEvent write fOnMyEvent; end;  При присваивании объекта в переменную со слабой ссылкой не происходит увеличение счётчика ссылок объекта на единицу. Аналогично, при очистке слабой ссылки не происходит уменьшение счётчика объекта на единицу.
    2. Не использовать анонимные методы, а использовать обычные указатели на метод: 
    Вместо TAnonymProc = reference to procedure; используем классический 
           TAnonymProc = procedure of object;

    Демо пример, где можно отследить утечку прикрепил.
    Полный код: 
     
    AnonMethodsCycle.zip
×
×
  • Создать...