Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   Share file via Provider (https://www.delphipraxis.net/200162-share-file-via-provider.html)

QuickAndDirty 25. Mär 2019 14:10


Share file via Provider
 
Android erlaubt ja nun nicht mehr dass man Dateien die in der Sandbox liegen per EMail-App verschickt.
Also wollte ich die Datei einfach "teilen" , wie es so schön heist...dann kann man sie per WhatsApp, Email oder Googledrive versenden.

Dazu ist soweit ich weiß folgendes notwendig.
Also ich muss setzen
->Projekt Optionen->Anwednung->Berechtinungsliste->Sichere Dateifreigabe = true
->Projekt Optionen->Anwednung->Berechtigungnen->Externen Speicher lesen = true
->Projekt Optionen->Anwednung->Berechtigungnen->Externen Speicher Schreiben = true

Habe hier also eine "Ein button App". Eine Actionlist und der Button hat eine Aktion vom Typ TShowShareSheetAction zugewiesen bekommen.
Damit kann man bitmaps "teilen".
Wie kann ich aber jede Art Datei teilen?

Delphi-Quellcode:
unit ShareFileForm;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Actions,
  FMX.ActnList, FMX.Controls.Presentation, FMX.StdCtrls,FMX.MediaLibrary.Actions,
  FMX.StdActns, ioutils;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ActionList1: TActionList;
    ShowShareSheetAction1: TShowShareSheetAction;
    procedure ShowShareSheetAction1BeforeExecute(Sender: TObject);
  private
    { Private-Deklarationen }

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

Const Loremipsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies sem a feugiat vulputate.'+
                   ' Nam euismod vitae nibh pulvinar ornare. Aliquam in tincidunt eros, eu viverra mi. Proin rutrum '+
                   'faucibus turpis vel pulvinar. Maecenas a mauris ac lectus feugiat dictum. Vestibulum mollis purus'+
                   ' quis massa finibus, non pellentesque lorem porta. Maecenas ullamcorper eleifend justo, et suscipit'+
                   ' ligula consectetur tincidunt. Fusce ut egestas ligula. In malesuada venenatis dui, et aliquet sem'+
                   ' hendrerit in. Nulla metus risus, laoreet vel ornare id, condimentum nec mauris. Vestibulum nibh urna,'+
                   ' pellentesque non semper non, condimentum sed mi. Nunc non justo et ante finibus euismod. Nunc nulla ante,'+
                   ' hendrerit ut pulvinar scelerisque, sollicitudin at tellus. Integer accumsan eu arcu in luctus.'+
                   ' In eros leo, convallis non ullamcorper nec, convallis eu augue.';

procedure TForm1.ShowShareSheetAction1BeforeExecute(Sender: TObject);
var fLogFile:String;
begin
{$IFDEF ANDROID}
  fLogFile := TPath.Combine(TPath.GetHomePath, 'Testfile.log' );
{$ENDIF}
{$IFDEF IOS}
  fLogFile := TPath.Combine(TPath.GetDocumentsPath, 'Testfile.log' );
{$ENDIF}
{$IFDEF WIN32}
  fLogFile := TPath.Combine(TPath.GetDirectoryName(paramstr(0)), TPATH.GetFileNameWithoutExtension(paramstr(0)) +'.log' );
{$ENDIF}
  TFile.WriteAllText( fLogFile, Loremipsum, TEncoding.UTF8);
  ShowShareSheetAction1.Bitmap.LoadFromFile(fLogFile);
end;

end.
meldet wie erwartet Laden des Bitmaps fehlgeschlagen...

Wie bekomme ich das mit einer textdatei hin?

QuickAndDirty 25. Mär 2019 15:13

AW: Share file via Provider
 
OK, das Projekt sieht jetzt so aus:

Ich kann in
FSharingService.Share(TargetControl, TextMessage, Bitmap);
nicht rein debuggen. Hat dazu jemand ne idee?

ActionUnit
Delphi-Quellcode:
unit ShareFileAction;

interface
uses System.Classes, System.Actions, System.Messaging, FMX.Types, FMX.MediaLibrary, FMX.ActnList, FMX.StdActns, FMX.Consts,
     FMX.Graphics, FMX.Controls;

type


{ TShowShareSheetAction }

  TShowShareSheetAction = class(TSysCommonAction)
  strict private
    FSharingService: IFMXShareSheetActionsService;
    FBitmap: TBitmap;
    FMessage: string;
    FOnBeforeExecute: TNotifyEvent;
  private
    procedure SetBitmap(const Value: TBitmap);
  protected
    procedure DoBeforeExecute;
    procedure CustomTextChanged; override;
    function IsSupportedInterface: Boolean; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function HandlesTarget(Target: TObject): Boolean; override;
    procedure ExecuteTarget(Target: TObject); override;
  published
    property Bitmap: TBitmap read FBitmap write SetBitmap;
    property TextMessage: string read FMessage write FMessage;
    property OnBeforeExecute: TNotifyEvent read FOnBeforeExecute write FOnBeforeExecute;
  end;

implementation

uses
  System.SysUtils, FMX.Platform, System.Types;

constructor TShowShareSheetAction.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FMessage := '';
  FBitmap := TBitmap.Create(0, 0);
  TPlatformServices.Current.SupportsPlatformService(IFMXShareSheetActionsService, FSharingService);
end;

procedure TShowShareSheetAction.CustomTextChanged;
begin
  Text := GetDefaultText(SOpenStandartServices);
end;

destructor TShowShareSheetAction.Destroy;
begin
  FSharingService := nil;
  FreeAndNil(FBitmap);
  inherited Destroy;
end;

procedure TShowShareSheetAction.DoBeforeExecute;
begin
  if Assigned(FOnBeforeExecute) then
    FOnBeforeExecute(Self);
end;

procedure TShowShareSheetAction.ExecuteTarget(Target: TObject);
var
  TargetControl: TControl;
begin
  DoBeforeExecute;
  inherited ExecuteTarget(Target);
  if Target is TControl then
    TargetControl := TControl(Target)
  else if ActionComponent is TControl then
    TargetControl := TControl(ActionComponent)
  else
    TargetControl := nil;
  if (Bitmap <> nil) and (FSharingService <> nil) then
    FSharingService.Share(TargetControl, TextMessage, Bitmap);//<<<-------------- ICH WILL WISSEN WAS DA PASSIERT
end;

function TShowShareSheetAction.HandlesTarget(Target: TObject): Boolean;
begin
  Result := Supported;
end;

function TShowShareSheetAction.IsSupportedInterface: Boolean;
begin
  Result := FSharingService <> nil;
end;

procedure TShowShareSheetAction.SetBitmap(const Value: TBitmap);
begin
  FBitmap.Assign(Value);
end;

end.
Formular unit
Delphi-Quellcode:
unit ShareFileForm;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Actions,
  FMX.ActnList, FMX.Controls.Presentation, FMX.StdCtrls,
  FMX.StdActns, ioutils, FMX.MediaLibrary.Actions,ShareFileAction ;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ActionList1: TActionList;
    procedure ShowShareSheetAction1BeforeExecute(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    ShowShareSheetAction1: TShowShareSheetAction;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

Const Loremipsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies sem a feugiat vulputate.'+
                   ' Nam euismod vitae nibh pulvinar ornare. Aliquam in tincidunt eros, eu viverra mi. Proin rutrum '+
                   'faucibus turpis vel pulvinar. Maecenas a mauris ac lectus feugiat dictum. Vestibulum mollis purus'+
                   ' quis massa finibus, non pellentesque lorem porta. Maecenas ullamcorper eleifend justo, et suscipit'+
                   ' ligula consectetur tincidunt. Fusce ut egestas ligula. In malesuada venenatis dui, et aliquet sem'+
                   ' hendrerit in. Nulla metus risus, laoreet vel ornare id, condimentum nec mauris. Vestibulum nibh urna,'+
                   ' pellentesque non semper non, condimentum sed mi. Nunc non justo et ante finibus euismod. Nunc nulla ante,'+
                   ' hendrerit ut pulvinar scelerisque, sollicitudin at tellus. Integer accumsan eu arcu in luctus.'+
                   ' In eros leo, convallis non ullamcorper nec, convallis eu augue.';

procedure TForm1.FormCreate(Sender: TObject);
begin
  ShowShareSheetAction1 := TShowShareSheetAction.Create(self);
  ShowShareSheetAction1.OnBeforeExecute := ShowShareSheetAction1BeforeExecute;
  Button1.Action := ShowShareSheetAction1;
end;

procedure TForm1.ShowShareSheetAction1BeforeExecute(Sender: TObject);
var fLogFile:String;
begin
{$IFDEF ANDROID}
  fLogFile := TPath.Combine(TPath.GetHomePath, 'Testfile.log' );
{$ENDIF}
{$IFDEF IOS}
  fLogFile := TPath.Combine(TPath.GetDocumentsPath, 'Testfile.log' );
{$ENDIF}
{$IFDEF WIN32}
  fLogFile := TPath.Combine(TPath.GetDirectoryName(paramstr(0)), TPATH.GetFileNameWithoutExtension(paramstr(0)) +'.log' );
{$ENDIF}
  TFile.WriteAllText( fLogFile, Loremipsum, TEncoding.UTF8);
  ShowShareSheetAction1.TextMessage := Loremipsum;
end;

end.

QuickAndDirty 25. Mär 2019 15:59

AW: Share file via Provider
 
Hmmm...
alle Lösungen im internet verlangen KastriFree.

gibt es Meinungen zu KastriFree?

QuickAndDirty 26. Mär 2019 15:21

AW: Share file via Provider
 
Also gut.
Habe die FileProvider Unit von Kastrifree in das projekt genommen....
alles andere rausgeschmissen
Delphi-Quellcode:
unit ShareFileForm;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Actions,
  FMX.ActnList, FMX.Controls.Presentation, FMX.StdCtrls,
  FMX.StdActns, ioutils, FMX.MediaLibrary.Actions
  {$IFDEF Android}
  , Androidapi.JNI.Os
  , Androidapi.JNI.GraphicsContentViewText
  , Androidapi.JNI.JavaTypes
  , Androidapi.Helpers
  , Androidapi.JNI.Net
  , Androidapi.JNI.Webkit
  , DW.Androidapi.JNI.FileProvider
  {$ENDIF}
  ;

type
  TForm1 = class(TForm)
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
    fLogFile:String;
    {$IFDEF Android}
      intent: JIntent;
    {$ENDIF}
    Procedure generateFile;
    Procedure ShareFileProvide(file_name:string);

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

Const Loremipsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies sem a feugiat vulputate.'+
                   ' Nam euismod vitae nibh pulvinar ornare. Aliquam in tincidunt eros, eu viverra mi. Proin rutrum '+
                   'faucibus turpis vel pulvinar. Maecenas a mauris ac lectus feugiat dictum. Vestibulum mollis purus'+
                   ' quis massa finibus, non pellentesque lorem porta. Maecenas ullamcorper eleifend justo, et suscipit'+
                   ' ligula consectetur tincidunt. Fusce ut egestas ligula. In malesuada venenatis dui, et aliquet sem'+
                   ' hendrerit in. Nulla metus risus, laoreet vel ornare id, condimentum nec mauris. Vestibulum nibh urna,'+
                   ' pellentesque non semper non, condimentum sed mi. Nunc non justo et ante finibus euismod. Nunc nulla ante,'+
                   ' hendrerit ut pulvinar scelerisque, sollicitudin at tellus. Integer accumsan eu arcu in luctus.'+
                   ' In eros leo, convallis non ullamcorper nec, convallis eu augue.';



procedure TForm1.Button2Click(Sender: TObject);
begin
  generateFile;
  ShareFileProvide(fLogfile);
end;

procedure TForm1.generateFile;

begin
{$IFDEF ANDROID}
  fLogFile := TPath.Combine(TPath.GetHomePath, 'Testfile.log' );
{$ENDIF}
{$IFDEF IOS}
  fLogFile := TPath.Combine(TPath.GetDocumentsPath, 'Testfile.log' );
{$ENDIF}
{$IFDEF WIN32}
  fLogFile := TPath.Combine(TPath.GetDirectoryName(paramstr(0)), TPATH.GetFileNameWithoutExtension(paramstr(0)) +'.log' );
{$ENDIF}
  TFile.WriteAllText( fLogFile, Loremipsum, TEncoding.UTF8);
end;

procedure TForm1.ShareFileProvide(file_name: string);
   {$IFDEF Android}
var
  ExtFile,deger,id:string;
  mime: JMimeTypeMap;
  ExtToMime: JString;
  Intent: JIntent;
  javafile:JFile;
  {$ENDIF}
begin
  {$IFDEF Android}
  javafile:=TJFile.JavaClass.init(StringToJString(file_name));

  ExtFile := AnsiLowerCase(StringReplace(TPath.GetExtension(file_name), '.', '',[]));

  mime := TJMimeTypeMap.JavaClass.getSingleton();

  ExtToMime := mime.getMimeTypeFromExtension(StringToJString(ExtFile));

  Intent := TJIntent.Create;
  id := JStringToString( TAndroidHelper.Context.getApplicationContext.getPackageName ) + '.fileprovider';

  deger := JURIToStr( TJFileProvider.JavaClass.getUriForFile( TAndroidHelper.Context,
                                                              StringToJString(id),
                                                              javafile)
                     );
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); //Intent.setAction(TJIntent.JavaClass.ACTION_SEND);

  Intent.setFlags(1);

  Intent.setDataAndType(StrToJURI(deger), ExtToMime);

  SharedActivity.startActivity(Intent);

  {$ENDIF}
end;

end.
Leider funktioniert es trotzdem nicht. :(

QuickAndDirty 27. Mär 2019 11:20

AW: Share file via Provider
 
Ich bekomme folgendes log und Exception aus dem code
Code:
file_name:/data/user/0/com.embarcadero.ShareFiletest/files/Testfile.txt

WriteAllText

javafile properties:
/data/user/0/com.embarcadero.ShareFiletest/files/Testfile.txt
/data/data/com.embarcadero.ShareFiletest/files/Testfile.txt
/data/user/0/com.embarcadero.ShareFiletest/files/Testfile.txt
Testfile.txt

txt
android.webkit.MimeTypeMap@74138ac
text/plain
ID: com.embarcadero.ShareFiletest.fileprovider
java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.embarcadero.ShareFiletest/files/Testfile.txt
Delphi-Quellcode:
procedure TForm1.ShareFileProvide;
  {$IFDEF ANDROID}
var
  ExtFile,deger,id: string;
  mime: JMimeTypeMap;
  ExtToMime: JString;
  Intent: JIntent;
  javafile: JFile;
  file_name: String;
  {$ENDIF}
begin
  {$IFDEF ANDROID}
  log.lines.Clear;
  file_name := TPath.Combine(TPath.GetHomePath, 'Testfile.txt' );
  log.lines.Add('file_name:'+file_name);
  log.lines.Add('');

  TFile.WriteAllText( file_name, Loremipsum, TEncoding.UTF8);
  log.lines.Add('WriteAllText');
  log.lines.Add('');

  javafile:=TJFile.JavaClass.init(StringToJString(file_name));
  log.lines.Add('javafile properties:');
  log.lines.Add(JStringToString(javafile.getAbsolutePath)) ;
  log.lines.Add(JStringToString(javafile.getCanonicalPath)) ;
  log.lines.Add(JStringToString(javafile.getPath)) ;
  log.lines.Add(JStringToString(javafile.getName)) ;
  log.lines.Add('');
  ExtFile := AnsiLowerCase(StringReplace(TPath.GetExtension(file_name), '.', '',[]));
  log.lines.Add(extfile);

  mime := TJMimeTypeMap.JavaClass.getSingleton();
  log.lines.Add(JStringToString(mime.toString));

  ExtToMime := mime.getMimeTypeFromExtension(StringToJString(ExtFile));
  log.lines.Add(JStringToString(ExtToMime));

  Intent := TJIntent.Create;
  id := JStringToString( TAndroidHelper.Context.getApplicationContext.getPackageName ) + '.fileprovider';
  log.lines.Add('ID: '+id);

  Try
    deger := JURIToStr( TJFileProvider.JavaClass.getUriForFile( TAndroidHelper.Context,
                                                                StringToJString(id),
                                                                javafile)
                       );
  Except
    on e:exception do
    Begin
      log.lines.Add(e.message);
      exit;
    End;
  End;

  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); //Intent.setAction(TJIntent.JavaClass.ACTION_SEND);

  Intent.setFlags(1);

  Intent.setDataAndType(TAndroidHelperEx.UriFromFile(javafile), ExtToMime); //  Intent.setDataAndType(StrToJURI(deger), ExtToMime);

  SharedActivity.startActivity(Intent);

  {$ENDIF}
end;
Wie kommt er darauf die Datei nicht finden zu können?
java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.embarcadero.ShareFiletest/files/Testfile.txt

QuickAndDirty 27. Mär 2019 12:17

AW: Share file via Provider
 
Ok des Rätselslösung:

die Datei
Android\Debug\provider_paths.xml
wird immer wieder mit diesem inhalt überschrieben
Code:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>
Wenn ich aber
diesen inhalt einbaue geht das teilen zumindest.
Code:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!--
  <external-path name="external_files" path="."/>
  <root-path name="root" path="."/>
  <external-files-path name="external_files" path="." />
  <external-path name="external_files" path="Android/data/com.embarcadero.ShareFiletest/files"/>
  -->
  <external-path name="external_files" path="Android/" />
</paths>
Lieder geht dieser inhalt bei jeder änderung an dateien verloren ^_^;


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz