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

Лидеры

  1. krapotkin

    krapotkin

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


    • Баллы

      3

    • Постов

      2 213


  2. Andrey Efimov

    Andrey Efimov

    Модераторы


    • Баллы

      1

    • Постов

      851


  3. aleksandrguru

    aleksandrguru

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


    • Баллы

      1

    • Постов

      96


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

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

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


    • Баллы

      1

    • Постов

      738


Популярный контент

Показан контент с высокой репутацией 26.12.2019 во всех областях

  1. В процессе разработки столкнулся с очень странной ситуацией, корни которой до сих пор неясны, но решение нашлось. Итак. Делфи 10.3.3. Чистое приложение - пустая форма и кнопка. Отлично работает на разных устройствах кроме Samsung Galaxy Tab A (2016). Android 5.1.1 Программа падает, не успев даже загрузиться. Любая. При этом она же, скомпилированная на другом компе, запускается нормально. И даже после изменения SDK/NDK на нем, ничего не падает. LogCat дает крайне странную картину java.lang.IllegalArgumentException: Unable to load native library: /data/app-lib/com.embarcadero.Project1-1/libProject1.so Начинаем экспериментировать с SDK, NDK и т.д. Поставил также хотфиксы для 10.3.3. Сразу скажу, SDK/NDK ставились отдельно через Android studio, не скачивались вместе с Delphi. Не торопитесь бросать чтение на этом месте!)) На другом компе, где все работает, все ставилось точно так же. Короче, очень много комбинаций версий SDK/NDK проверено. Результат такой. При постепенном понижении версии NDK все взлетело при NDK v22. При этом версия SDK видимо такого большого влияния не имеет, потому что этот вариант нормально работает Повторюсь. На других устройствах все работало и на более новых Ndk. Xiaomi Mi Pad4 , Samsung Galaxy Tab A (2019), Xiaomi Redmi 5 и 5Plus Спасибо за участие и помощь в разборе завалов @Andrey Efimov
    2 балла
  2. Я делаю так: 1.Создаю файл базы (БД) например для Виндовс Acces (пример моего в приложении). 2.Создаю файл TreeView.dat. 3.Подключаюсь к БД. 4.Создаю нове ветки так: //Ввести ветку procedure TForm_Glavn.SpeedButton_vvod_vetkiClick(Sender: TObject); begin //проверка наличия текста в Едите if Edit_Mame_Vetok.Text = '' then begin MessageDl.MessageDlg('Вы не ввели название ветки!', mtInformation,[mbYes],0); Abort; end; TreeView1.Items. Add (TreeView1. Selected, Edit_Mame_Vetok.Text) ; //база Query_Glav.Insert; Query_Glav.FieldByName('Dat').AsString:=DateToStr(Now); Query_Glav.FieldByName('Imya_vetok').AsString:=Edit_Mame_Vetok.Text; Query_Glav.FieldByName('Opisanie').AsString:=Memo_opisanie.Text; Query_Glav.Post; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 5.Создаю подветки так: //Ввести подветку procedure TForm_Glavn.SpeedButton_vvod_podvetkiClick(Sender: TObject); begin if TreeView1.Selected = nil then begin MessageDl.MessageDlg('Вы не выбрали в какой ветке делаем подветку!', mtInformation,[mbYes],0); Exit; //если не выбрана ветка выходим end; //проверка наличия текста в Едите if Edit_Mame_Vetok.Text = '' then begin MessageDl.MessageDlg('Вы не ввели название ветки!', mtInformation,[mbYes],0); Abort; end; TreeView1.Items.AddChild (TreeView1. Selected, Edit_Mame_Vetok.Text); //база Query_Glav.Insert; Query_Glav.FieldByName('Dat').AsString:=DateToStr(Now); Query_Glav.FieldByName('Imya_vetok').AsString:=Edit_Mame_Vetok.Text; Query_Glav.FieldByName('Opisanie').AsString:=Memo_opisanie.Text; Query_Glav.Post; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 6.Прикрепляю файл так: // Прикрепить файл procedure TForm_Glavn.SpeedButton_FileClick(Sender: TObject); var IconStream:TMemoryStream; begin if TreeView1.Selected = nil then begin MessageDl.MessageDlg('Вы не выбрали в какой ветке делаем подветку!', mtInformation,[mbYes],0); Exit; //если не выбрана ветка выходим end; OpenDialog1.InitialDir:=Base; if Opendialog1.Execute then begin //заносим файл в потоке SpeedButton_File.Caption:='Подождите......'; Application.ProcessMessages; IconStream:=TMemoryStream.Create; IconStream.LoadFromFile(OpenDialog1.FileName); //становимся в невидимой таблице на указанной модели Query_Glav.Locate('Imya_vetok',Edit_Mame_Vetok.Text,[loPartialKey, loCaseInsensitive]); Query_Glav.Edit; if (ExtractFileExt(Opendialog1.FileName) = '.pdf')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=3; if (ExtractFileExt(Opendialog1.FileName) = '.docx')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=2; if (ExtractFileExt(Opendialog1.FileName) = '.jpg')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=0; if (ExtractFileExt(Opendialog1.FileName) = '.rar')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=1; (Query_Glav.FieldByName('File') as TBlobField).LoadFromStream(IconStream); IconStream.Free; Application.ProcessMessages; MessageDl.MessageDlg('Файл добавлен в базу!', mtInformation,[mbYes],0); SpeedButton_File.Caption:=' Прикрепить файл'; end else MessageDl.MessageDlg('Ошибка ввода!', mtInformation,[mbYes],0); end; 7. Удаляю ветку или подветку так: //Удалить ветку/ подветку procedure TForm_Glavn.SpeedButton_DeleteClick(Sender: TObject); begin if TreeView1.Items.Count = 0 then //проверка наличия веток вообще begin MessageDl.MessageDlg('Так нет же веток!', mtInformation,[mbYes],0); Abort; end; if TreeView1.Selected.HasChildren=True then //проверка наличия подветки begin MessageDl.MessageDlg('Сначала удалите подветку!', mtInformation,[mbYes],0); Image1.Refresh; Abort; end; if TreeView1.Selected.HasChildren=False then //проверка наличия подветки begin SpeedButton_Delete.Caption:='Подождите.....'; Application.ProcessMessages; //становимся в невидимой таблице на указанной ветке Query_Glav.Locate('Imya_vetok',TreeView1.Selected.Text,[loPartialKey, loCaseInsensitive]); if Query_Glav.FieldByName('Imya_vetok').AsString <> '' then Query_Glav.Delete;//удаляем в базе Application.ProcessMessages; TreeView1.Items.Delete(TreeView1.Selected); //удаляем в дереве Application.ProcessMessages; Image1.Refresh; Application.ProcessMessages; SpeedButton_Delete.Caption:=' Удалить ветку/ подветку'; end; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 8. Переименовываю ветки так: //Переименовать ветку/ подветку procedure TForm_Glavn.SpeedButton3Click(Sender: TObject); begin //проверка наличия текста в Едите if Edit_Mame_Vetok.Text = '' then begin MessageDl.MessageDlg('Вы не ввели название ветки!', mtInformation,[mbYes],0); Abort; end; //становимся в невидимой таблице на указанной модели Query_Glav.Locate('Imya_vetok',TreeView1.Selected.Text,[loPartialKey, loCaseInsensitive]); TreeView1.Selected.Text:=Edit_Mame_Vetok.Text; //база Query_Glav.Edit; Query_Glav.FieldByName('Dat').AsString:=DateToStr(Now); Query_Glav.FieldByName('Imya_vetok').AsString:=Edit_Mame_Vetok.Text; Query_Glav.FieldByName('Opisanie').AsString:=Memo_opisanie.Text; Query_Glav.Post; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 9.Открываю прикреплённый файл так: // Открыть прикреплённый файл отдельно procedure TForm_Glavn.SpeedButton4Click(Sender: TObject); var ImageData:TMemoryStream; begin if TreeView1.Selected = nil then begin MessageDl.MessageDlg('Вы не выбрали в какой ветке делаем подветку!', mtInformation,[mbYes],0); Exit; //если не выбрана ветка выходим end; //становимся в невидимой таблице на указанной модели Query_Glav.Locate('Imya_vetok',Edit_Mame_Vetok.Text,[loPartialKey, loCaseInsensitive]); ImageData:=TMemoryStream.Create; (Query_Glav.FieldByName('File') as TBlobField).SaveToStream(ImageData); ImageData.Position:=0; if ImageData.Size<>0 then begin if Query_Glav.FieldByName('RashirenieFile').AsInteger=3 then Path:=Base+'\Temp\Dokument.pdf'; if Query_Glav.FieldByName('RashirenieFile').AsInteger=2 then Path:=Base+'\Temp\Dokument.docx'; if Query_Glav.FieldByName('RashirenieFile').AsInteger=0 then Path:=Base+'\Temp\Dokument.jpg'; if Query_Glav.FieldByName('RashirenieFile').AsInteger=1 then Path:=Base+'\Temp\Dokument.rar'; ImageData.SaveToFile(Path); ImageData.Free; ImageData:=nil; if FileExists(Path) then begin ShellExecute (0, 'open', pChar(Path), nil, nil, SW_SHOW); end else MessageDl.MessageDlg('Файл'+Path+' в папке Data не найден.', mtInformation,[mbYes],0); end else MessageDl.MessageDlg('В этой ветке документа нет.', mtInformation,[mbYes],0); end;
    1 балл
  3. Есть ещё вот такие компоненты: CData Enterprise Connectors
    1 балл
  4. У меня в работе два приложения, и оба они не предназначены для Play market, так как имеют ограниченный круг использования, по сути, чисто внутрикорпоративные. Так что нежелательно и выкладывание их и на альтернативные магазины приложений. Автоматически возникает вопрос обновления. Если в первый раз мы можем установить приложение сами при помощи админов, то обновлять их не так просто. А контингент пользователей не справится с "скачайте APK по ссылке, найдите, куда его скачал браузер, и запустите вручную именно последний скачанный, а не какой попало"... Простейший способ - дать приложению скачать свежую копию с сайта и натравить на полученный файл системный инсталлер. Вот только свежие Andoird делать это напрямик запрещают. Нужен filepropvider. Целый день шуровал по мануалам и YT, Вот то что получилось в результате. Если у вас 10.3.3 как у меня, уже можно не вносить <provider>...</provider> в манифест и свой файл file_paths.xml (или как вам его советуют назвать в интернетах) в деплой. Теперь все это делается хоть несколько странно и однобоко, но автоматически, путем установки галочки Secure File Sharing после этого в манифесте автоматически пропишется один из вариантов размещения файлов, которые вы можете найти в интернете. Используется алиас external-path файл, показанный на рисунке, создается автоматически самой делфи. теперь остается отгадать, какой путь реально подставится вместо "." Как показала практика, все пути выглядят не так, как кажется, если исходить из простого здравого смысла. Целый день использования GetHomeDir и других полезных методов TPath завел меня совсем в тупик. Оказалось все проще (?) st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; ... OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); обратите внимание, в provider_paths мы задаем external-paths, а в коде ищем ExternalCacheDir.!!! (For.Unbelievably.Creative.Knowers!) Потом все просто. FApkUri передаем в интент и запускаем итоговый код примерно таков. (скачивание в потоке с использованием небольшого собственного API, но там ничего важного, можно не обращать внимания) procedure TasdSettingsFrame.bDownloadClick(Sender: TObject); begin {$IFDEF ANDROID} bDownload.Enabled := False; DownloadAndRun(); {$ENDIF} end; {$IFDEF ANDROID} procedure TasdSettingsFrame.DownloadAndRun(); begin ttask.Run(procedure var aapi:TasdAPI; st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; begin st := TMemoryStream.Create; aapi := TasdAPI.Clone(_API); try aapi.OnReceiveData := OnReceiveData; aapi.getApk(st); if aapi.Err.Code=0 then begin OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); TThread.Synchronize(nil,procedure begin bDownload.Enabled := true; StartActivity(FApkUri); end); end; finally st.Free; aapi.Free; end; end); end; procedure StartActivity(ApkUri: Jnet_Uri); var Intent: JIntent; begin Intent := TJIntent.Create(); Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK or TJIntent.JavaClass.FLAG_ACTIVITY_CLEAR_TOP or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION or TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION); Intent.setDataAndType(apkuri, StringToJString('application/vnd.android.package-archive')); TAndroidHelper.Activity.startActivity(Intent); end; procedure TasdSettingsFrame.OnReceiveData(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean); begin tthread.Synchronize(nil, procedure begin pb1.Max := AContentLength; pb1.Value := AReadCount; end); end; {$ENDIF} Вопросы остались конечно, почему так странно с каталогами, но выяснять пока нет желания. Работает - не трожь. Всем удачи. UPD. Для того, чтобы системный инсталлер запускался, нужно не забыть отметить еще одну галочку
    1 балл
  5. У TMS был компонент готовый https://www.tmssoftware.com/site/tmsfnccloudpack.asp
    1 балл
  6. Все правильно получаете, кодировка тут не при чем. Согласно спецификации "DNS Packet Structure", вы получаете не строку, а пакет который нужно разобрать. К примеру если запрос будет "nslookup www.google.ru 127.0.0.1", то там где вы получаете имя хоста будет строка "''#3'www'#6'google'#2'ru'#0#0#1#0#1". Парсинг простейший: #3 - означает что далее идут 3 символа хоста 'www' - вот ожидаемые 3 символа #6 - далее идут еще 6 символов хоста 'google' - ага, вот они #2 - ну и еще 2 символа 'ru' - ура, они здесь #0 - конец имени хоста, складываем в кучу, перемежая точками и получаем www.google.ru #0 - дальше у нас служебная информация... #1 #0 #1 Вот как то так. P.S. А зачем вам на таком низком уровне работать? Может использовать IdDNSServer : TIdDNSServer ? P.P.S. Правильно Memo1.Lines.Add(BytesToString(AData,12)); //(12, а не 13)
    1 балл
Эта таблица лидеров рассчитана в Москва/GMT+03:00
×
×
  • Создать...