0

Goal: Using an iOS native method, push a user made picture onto their Instagram feed in C#.

public bool ShareImage(byte[] imageByte)
        {
            bool result = false;

            //string fileName = "xxx.png";
            //string path = Path.Combine(FileSystem.CacheDirectory, fileName);
            //File.WriteAllBytes(path, imageByte);
            NSData data = NSData.FromArray(imageByte);
            UIImage image = UIImage.LoadFromData(data);
            
            //NSUrl url = NSUrl.FromString($"instagram://library?AssetPath={path}"); // Only opens
            NSUrl url = NSUrl.FromString($"instagram://library?LocalIdentifier={1}");
            if (UIApplication.SharedApplication.CanOpenUrl(url))
            {
                UIApplication.SharedApplication.OpenUrl(url);
            }
            return result;
        }

As far as I'm aware the way I have to do this is to save my image to the device and get a Local Identifier for this. I have constructed this from the snippets of objective-c code I have seen. Sharing photos only works with the native app installed, as I have learnt from my trials to get the facebook module working.

Edit: Using PHAssetChangeRequest from the iOS Photos namespace does not work. A collegue has pointed out to me about the possibility of saving then using a photo picker to get the PHAsset for the Local Identifier. But this is an extra step I do not want the users of the App to go through. Better to just remove Instagram support as I just can go through the generic share method as shown below. The disadvantage of this method is that the user has then to pick the medium to share over.

public async void ShareImage(byte[] imageByte)
        {
            string fileName = "xxx.png";
            string path = Path.Combine(FileSystem.CacheDirectory, fileName);
            File.WriteAllBytes(path, imageByte);
            await Share.RequestAsync(
                new ShareFileRequest()
                {
                    File = new ShareFile(path),
                    Title = "xxx"
                }
                );
        }

Edit 2 Tried a different way using UIDocumentInteractionController but it is showing nothing and not posting, it is not throwing any exceptions to give me any clues as to what I'm doing wrong.

public bool ShareImage(byte[] imageByte)
        {
            bool result = false;

            string fileName = "xxx.igo";
            string path = Path.Combine(FileSystem.CacheDirectory, fileName);
            File.WriteAllBytes(path, imageByte);
            //string caption = "xxx";
            string uti = "com.instagram.exclusivegram";
            UIImageView view = new UIImageView();
            //UIDocumentInteractionController controller = UIDocumentInteractionController.FromUrl(NSUrl.FromString(path));
            UIDocumentInteractionController controller = new UIDocumentInteractionController
            {
                //controller.Url = NSUrl.FromString(path);
                Url = NSUrl.FromFilename(path),
                Uti = uti
            };
            //CoreGraphics.CGRect viewDimensions = new CoreGraphics.CGRect(0, 0, 200, 100);
            
            _ = controller.PresentOpenInMenu(CoreGraphics.CGRect.Empty, view, true);
            //_ = controller.PresentOpenInMenu(viewDimensions, view, true);
            return result;
        }

Edit 3 Using

UIView view = new UIImageView();
            if (UIApplication.SharedApplication.KeyWindow.RootViewController is UIViewController uiController && uiController.View != null)
            {
                view = uiController.View;
            }

I was able to get the possible share options to show. I was logged in to Instagram using the native App, but the post did not show.

1 Answers1

0
  1. Change

    Url = NSUrl.FromFilename(path)

    to

    Url = new NSUrl(path,false)

    The second way is pointing to the correct file path not the file name .

  2. Change

    controller.PresentOpenInMenu(CoreGraphics.CGRect.Empty, view, true);

    to

    controller.PresentOptionsMenu(UIScreen.MainScreen.Bounds, (UIApplication.SharedApplication.Delegate as AppDelegate).Window, true);

    Show UIDocumentInteractionController inside current Window and set the proper frame.

ColeX
  • 14,062
  • 5
  • 43
  • 240
  • I have changed the url initialisation. But with presenting, the issue is that the class itself is called from Xamarin, and has no knowledge of a UIImageView and no reference to use. Unless there is also a way to get that somehow. – Lloyd Woollard Jan 05 '22 at 08:23
  • Are you developing Xamarin.Forms or Xamarin.iOS ? – ColeX Jan 05 '22 at 08:58
  • Xamarin.Forms. This is a native iOS class(public class ShareServiceInstagramiOS : IShareServiceInstagram) that is called from a Xamarin page. I have to implement both iOS and Android versions which is why I only send the image. The image itself is altered using Skia, and the byte[] comes from this. – Lloyd Woollard Jan 05 '22 at 09:12
  • Check my update code , change `View` to current Window. – ColeX Jan 06 '22 at 03:58
  • Still nothing. I must be doing something wrong at a deeper level. The Window is there, the bounds have the same bound value as the window. It is unlikely a problem with the Xamarin overlaying the native iOS. The dimensions for a camera preview which also runs native and full-screen has the same bound dimensions. The Android version is using an Intent and has a much different layout, so is not helpful here either. – Lloyd Woollard Jan 06 '22 at 07:31
  • If possible could you provide us a basic , reproducible project to test ? Since it is working on my side . You can simply upload it to github and attach the link here . – ColeX Jan 07 '22 at 01:38
  • Unfortunatly a basic reproducable App without all the other stuff and without customer secrets is currently a lot of extra work. Since this works only partially I shall have to convince the customer to go down the default path (shown in my first Edit). Thank you for your help to try and correct this for me. – Lloyd Woollard Jan 11 '22 at 07:47