1

I want to share the URL with the file and the message.

However, it seems that only one of the two can be shared using Share of Essentials.

I can implement both, but I don't know how to send both at the same time.

So I proceeded with the customization as follows.

Xamarin.From

public interface IShare
    {
        void Share(string subject, string message, byte[] image);
    }

private async void Button_Clicked(object sender, EventArgs e)
        {
            var imageStream = await ScreenShot.CaptureImageAsync();

            DependencyService.Get<IShare>().Share(" ", "Hello - https://www.naver.com/", GetImageBytes(imageStream));

        }

private byte[] GetImageBytes(Stream stream)
            {
                byte[] ImageBytes;
                using (var memoryStream = new System.IO.MemoryStream())
                {
                    stream.CopyTo(memoryStream);
                    ImageBytes = memoryStream.ToArray();
                }
                return ImageBytes;
            }

Android Code

public void Share(string subject, string message, byte[] image)
{
    ShareMultipleFilesRequest(message,image);
}

static Task ShareMultipleFilesRequest(string message, byte[] image)
{
    var intent = new Intent(Intent.ActionSend);

    intent.PutExtra(Intent.ExtraText, message);

    intent.SetType("image/png");
    intent.SetFlags(ActivityFlags.GrantReadUriPermission);

    string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
    string filename = System.IO.Path.Combine(path, "CaptureScreen.png");

    System.IO.File.WriteAllBytes(filename, image);

    Java.IO.File sharedFile;

    sharedFile = new Java.IO.File(filename);

    System.Console.WriteLine($"{sharedFile.IsAbsolute}");

    intent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(new Java.IO.File(sharedFile.AbsolutePath)));

    intent.PutExtra(Intent.ExtraTitle, "Share Image");

    var chooserIntent = Intent.CreateChooser(intent, "Share Image" ?? string.Empty);

    var flags = ActivityFlags.ClearTop | ActivityFlags.NewTask;

    chooserIntent.SetFlags(flags);

    Xamarin.Essentials.Platform.AppContext.StartActivity(chooserIntent);

    return Task.CompletedTask;
}

iOS Code

 public void Share(string subject, string message, byte[] image)
        {

            var chartImage = new UIImage(NSData.FromArray(image));
            var mess = NSObject.FromObject(message);

            var activityItems = new[] { mess, chartImage };
            var activityController = new UIActivityViewController(activityItems, null);

            var topController = UIApplication.SharedApplication.KeyWindow.RootViewController;

            while (topController.PresentedViewController != null)
            {
                topController = topController.PresentedViewController;
            }

            topController.PresentViewController(activityController, true, () => { });
        }

But Android Messages are shared. But the image is not shared. May I know what is the problem? Or do I know how to send both at the same time.

장주명
  • 43
  • 6
  • 1
    "doesn't work" is not a helpful description of the problem. Do you get an error or exception? Does it crash? Does it do anything? Have you debugged it? What specifically is happening (or not happening) when this code executes? – Jason Sep 15 '21 at 12:03
  • oh Sorry, Messages are shared. But the image is not shared. – 장주명 Sep 15 '21 at 12:27
  • https://stackoverflow.com/questions/20333186/how-to-share-image-text-together-using-action-send-in-android – Jason Sep 15 '21 at 12:32

1 Answers1

1

If you are using Android 7.0 or above,you should use FileProvider to deal with your uri.

add provider into your manifest:

<application ...>
  <provider
       android:name="androidx.core.content.FileProvider"
       android:authorities="${applicationId}.provider"
       android:exported="false"
       android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
  </provider>
</application>

and add the provider_paths.xml into Resoures/xml:

<?xml version="1.0" encoding="utf-8" ?>
<paths>
  <files-path
      name="files-path"
      path="." />
  <cache-path
      name="cache-path"
      path="." />
  <external-path
      name="external_storage_root"
      path="." />
  <external-files-path
      name="external_file_path"
      path="." />
  <external-cache-path
      name="external_cache_path"
      path="." />
  <root-path
      name="root-path"
      path="" />
</paths>

and share method in android project:

 private Task ShareMultipleFilesRequest(string message, byte[] image)
    {
        var intent = new Intent(Intent.ActionSend);

        intent.PutExtra(Intent.ExtraText, message);

        intent.SetType("image/png");
        intent.SetFlags(ActivityFlags.GrantReadUriPermission);

        string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
        string filename = System.IO.Path.Combine(path, "CaptureScreen.png");

        System.IO.File.WriteAllBytes(filename, image);

        Java.IO.File sharedFile;

        sharedFile = new Java.IO.File(filename);

        System.Console.WriteLine($"{sharedFile.IsAbsolute}");

        intent.PutExtra(Intent.ExtraStream, FileProvider.GetUriForFile(Xamarin.Essentials.Platform.AppContext, Xamarin.Essentials.Platform.AppContext.PackageName + ".provider", sharedFile));

        intent.PutExtra(Intent.ExtraTitle, "Share Image");

        var chooserIntent = Intent.CreateChooser(intent, "Share Image" ?? string.Empty);

        var flags = ActivityFlags.ClearTop | ActivityFlags.NewTask;

        chooserIntent.SetFlags(flags);

        Xamarin.Essentials.Platform.AppContext.StartActivity(chooserIntent);

        return Task.CompletedTask;
    }

and in your Activity,you could receive the message and uri like:

Note:here i set the Acitivity attribute LaunchMode =Android.Content.PM.LaunchMode.SingleTask,then overwrite the OnNewIntent method to receive the share content.

protected override void OnNewIntent(Intent intent)
    {
        base.OnNewIntent(intent);
        if (intent != null)
        {
            string message = intent.GetStringExtra(Intent.ExtraText);
            var uri = intent.GetParcelableExtra(Intent.ExtraStream);
        }
    }
Leo Zhu
  • 15,726
  • 1
  • 7
  • 23
  • Thank you so much! This is the answer which works. I have been at this since a full 48 hours and was so frustrated! Especially, as there are new restrictions in file storage access due to Android. – Joginder Tanikella Jun 06 '22 at 13:46