0

So, either I am asking incorrectly, or it isn't possible, let's see which...

If my app (Xamarin.Forms) is launched from another app, in order to get a url from my app, how do I return that data to the calling app? I wrongly assumed SetResult and Finish, I also wrongly assumed StartActivityForResult, but there has to be a way to do this. I know how to get data INTO my app from another app, but not the same in return.

POSSIBLE PARTIAL SOLUTION -- UPDATE, FAILS

So I have to setup an interface in my PCL, and call the method from the listview item selected handler, in the Android app I can then do this:

Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_url"));
setResult(Activity.RESULT_OK, result);
finish();

(source: https://developer.android.com/training/basics/intents/filters.html)

Is this looking right, and how would I implement the same thing on iOS?

END

I deleted my previous question because I couldn't explain the problem clearly, so here goes.

I have a Xamarin Forms app, I want to use a section of this app as a gallery. Currently I have images displayed in a list, and I have an Intent filter set that launches this page when you select the app as the source for an image (such as upload image on Facebook).
My issue is that I don't know how to return the data (the selected image) back to the app / webpage that made the request. In android I understand that you would use StartActivityForResult and OnActivityResult to handle this, but I am using Xamarin Forms (Android, iOS, UWP) and can't really find a solution that could be used cross-platform.

Just a link to documentation that covers this would be great, but if you have an example then even better.

Thanks

EDIT

Here is the code used to launch the app, I am interested in getting data back from the Intent.ActionPick after the user has selected an image from a ListView, which is in a ContentPage in the PCL.

[Activity(Label = "", Icon = "@drawable/icon", Theme = "@style/DefaultTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
          ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = @"*/*")]
[IntentFilter(new[] { Intent.ActionView, Intent.ActionPick, Intent.ActionGetContent }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryOpenable }, DataMimeType = @"*/*")]
public class MainActivity : FormsAppCompatActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        try
        {
            base.OnCreate(bundle);

            CurrentPlatform.Init();
            Xamarin.Forms.Forms.Init(this, bundle);

            App _app = new App();
            LoadApplication(_app);

            if (Intent.Action == Intent.ActionSend)
            {
                var image = Intent.ClipData.GetItemAt(0);
                var imageStream = ContentResolver.OpenInputStream(image.Uri);
                var memOfImage = new System.IO.MemoryStream();
                imageStream.CopyTo(memOfImage);
                _app.UploadManager(memOfImage.ToArray());  //This allows me to upload images to my app
            }
            else if (Intent.Action == Intent.ActionPick)
            {
                _app.SelectManager(); //here is where I need help
            }
            else
            {
                _app.AuthManager(); //this is the default route
            }
        }
        catch (Exception e)
        {
        }
    }
Shaine Fisher
  • 315
  • 1
  • 3
  • 20
  • So if I understand you know a solution for Android but not for IOS and UWP? Or do you have 3 separated solutions but don't know how to make them crossplatform? – Jordy Dieltjens Jul 06 '17 at 09:44
  • No, I think there will need to be a structural change to the app to make this work at all. I don't know how to implement this. At the moment I have a forms PCL, and the standard single activity in each platform app. – Shaine Fisher Jul 06 '17 at 09:51
  • You said in your question you might know how to do it in Android, how and where did you find it? if you share that with us we might be able to find solutions for the 2 other platforms. And after that it's just dependency injection so you can call it in your PCL – Jordy Dieltjens Jul 06 '17 at 09:54
  • It was just a hypothesis, essentially, if I launch my forms app from an intent designed to allow the user to select an image, is there a way to return the selected image back to the requesting source using forms, or does it have to be done in a platform specific way. If its platform specific then I have an issue. There is also a possibility that a custom renderer, such as this example https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/listview/ but I'm not sure what to do. – Shaine Fisher Jul 06 '17 at 10:10
  • Actually, StartActivityForResult seems to be more for getting data into my app from another app, which is the opposite to what I want :( – Shaine Fisher Jul 06 '17 at 10:24
  • 1
    You could perhaps use the OnClose ? This happens when the app closes so that might be an idea. Do you have an idea of what you got to return? (bitmap, base64 string) – Jordy Dieltjens Jul 06 '17 at 10:50
  • The url of an Image, that I have stored in Azure storage. So in essence, user selects an image in the list view, the list view action return the url to the OnClose method and then closes the app? I like that. Is this is 'proper' way, or are we just working on possible solutions? – Shaine Fisher Jul 06 '17 at 11:23
  • The only problem I see at the moment is how the other app is gonna acces the data you putted in your onclose, the other application is it something that you made or it should work on any application? – Jordy Dieltjens Jul 06 '17 at 11:29
  • It should work on any, when you click Add Photo, for example on Facebook, my app opens (that bit works), then you select the image and return the url to whatever app or website requested the data. This is launched from an intent time pick an image. – Shaine Fisher Jul 06 '17 at 11:44
  • @JordyDieltjens what do you think of the solution I added to the top of the question? All I have to do now is work out how to get it into a class that implements the interface I am using, that looks like it might be a problem :( – Shaine Fisher Jul 06 '17 at 13:36
  • Still no nearer to a solution, the above suggested code runs, but as expected , nothing really happens, the code executes, but no result is returned, and nothing is destroyed. – Shaine Fisher Jul 08 '17 at 11:15
  • 1
    Atm i'm oon vacation so cant help you. If youbmake abgithub project of this i would like to help you since this sounds really interesting and somethong i havent seen in Xamarin yet – Jordy Dieltjens Jul 08 '17 at 23:35
  • 1
    It seems that you will need platform dependant implementation anyway. Are you OK with implementing this functionality differently on different platforms? – Yuri S Jul 11 '17 at 21:09
  • 1
    Another less elegant option is to use cross-platform file storage and provide your URL as text in file. You can specify developer of another app where is it but not sure if it's good enough. I would say if you need this as internal app you can do whatever you want but for production app you need platform specific implementations – Yuri S Jul 11 '17 at 21:12
  • I have no problem using platform dependant solutions, but I don't know what to call, I have been struggling with Android to get it to do what I want. – Shaine Fisher Jul 12 '17 at 04:53
  • I was trying to use set result and finish (Android). I did this by creating an interface and using dependency injection to call the code when a user selected an item in the list, however, the code is called and the Intent is created but setResult and finish don't appear to do anything although it breaks at the right place in the debugger. The Activity is supposed to be closed and the result returned, this doesn't happen. – Shaine Fisher Jul 12 '17 at 06:36
  • Is this what you want or I get this wrong? https://stackoverflow.com/questions/24029050/how-to-make-my-android-app-to-act-as-image-picker Please add to your comments "@YuriS" so I get notification when you post your comment – Yuri S Jul 12 '17 at 17:12
  • @YuriS, as I see it that is how you set the Intent in order for your app to launch based on mime/file type, that bit I have working. My manifest if perfect, I think. – Shaine Fisher Jul 13 '17 at 05:21
  • Summary: User goes to Facebook, clicks Post Image, chooser opens and shows apps list, and then user selects my app, app opens (because of Intent) and opens page using LoadApplication() (forms app PCL), displays images in a list, user selects image, handler passes url of the image to method (interface, platform code), platform code creates result Intent (Android)... Everything after that is a mystery, that is the question. – Shaine Fisher Jul 13 '17 at 06:26
  • Where are images coming from? Is it resource images of your app or files? – Yuri S Jul 13 '17 at 16:57
  • @YuriS they are stored in Azure. – Shaine Fisher Jul 13 '17 at 17:14
  • 1
    can we go to chat room, so I better understand what you are doing? I can create chat room or you can do it – Yuri S Jul 13 '17 at 17:18
  • I don't know how :( – Shaine Fisher Jul 13 '17 at 17:38
  • Are you downloading images from Azure before you allow them to be selected from your app (if yes then where?) or you want to return URI which points to Azure? – Yuri S Jul 13 '17 at 17:39
  • @YuriS I want to return a Url to the image in Azure storage. – Shaine Fisher Jul 13 '17 at 17:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/149159/discussion-between-yuri-s-and-shaine-fisher). – Yuri S Jul 13 '17 at 17:41

2 Answers2

1

You can use static public class to save and access results like:

public static class StaticClass
{
     public static int Result;
}
Ivan Ičin
  • 9,672
  • 5
  • 36
  • 57
  • I know it's my explanation that is lacking, I understand that, but all I want to do is allow a user to select an image from a list and return the result (a Url) back to the caller, which could be another app, or a webpage, where you want to upload an image. I have the app launching the right section, the list is populated, and the user can select the image, intents work fine, data is present, it's the actual passing the data back (such as using the possible partial solution above) that is killing me, and it's the most important part. – Shaine Fisher Jul 11 '17 at 12:04
  • @ShaineFisher it is quite legal to ask for a particular way of handling the things, but there is nothing that you can't do with the alternative method I have explained above as far as I can see. I am not an expert on Xamarin.Forms (I use Xamarin.iOS and other native forms of Xamarin), but I think I can say that you can't do what you want in iOS natively so it is quite possible that Xamarin.Forms don't support that either. – Ivan Ičin Jul 11 '17 at 12:11
  • 1
    Thanks for the answer, it looks like a complete waste of a lot of time has occurred, and I now have to rewrite an entire app because of a single bit of functionality that just isn't there, I was hoping someone would have a workable answer, or a plugin that covered this sort of thing, I mean it seems like a core feature really, get data in, hand data out again. I'm going to go and scream over here for a while. – Shaine Fisher Jul 11 '17 at 12:15
  • @ShaineFisher, in general in modern languages there is something that is called a principle of separation of data, business logic and user interface. What you ask for feels like a breaking of this principle and probably that's why it isn't supported. – Ivan Ičin Jul 11 '17 at 12:30
  • No, I don't think that's the reason. At the end of the day you can either pass data back to a calling app when using forms, or you can't. And in this case I have good separation, but what I want is a method to push data back to the caller when the user selects an item in a list. – Shaine Fisher Jul 11 '17 at 15:01
  • @ShaineFisher Anything you can do in native iOS and native Android, you can also do in native Xamarin **&** in Xamarin Forms. Native Android [allows passing data between apps](https://stackoverflow.com/a/16733453/3850012) using intents. I have not tried it myself but from the examples I have seen, [one way to do this](https://stackoverflow.com/a/38609877/3850012) would be to get the calling app's class names. Also a [ContentProvider](https://developer.android.com/guide/topics/providers/content-providers.html) maybe be another answer. – hvaughan3 Jul 13 '17 at 18:59
  • @hvaughan3 the question here is not that at all, but whether it can be done in native apps (and then on Xamarin on respective platforms) and then again not on Android because everybody knows it can be done on Android, OP did that in Android already. – Ivan Ičin Jul 14 '17 at 07:30
  • 2
    @hvaughan3 it happens to me too :). – Ivan Ičin Jul 14 '17 at 20:22
1

It seems you cannot use remote URI to provide to calling app. Some posts I checked suggest to store the file locally and provide it's path to calling app. To avoid memory leak with many files stored I suggest to use the same file name then you will have only one file at any moment.

One more note. I tested this solution in facebook. Skype doesn't seem to accept that and, again, the posts I checked saying that Skype doesn't handle Intent properly (not sure what that means).

Now to solution. In main activity for example in OnCreate method add the follow. ReturnImagePage is the name of my page class where I select an image

        Xamarin.Forms.MessagingCenter.Subscribe<ReturnImagePage, string>(this, "imageUri", (sender, requestedUri) => {

            Intent share = new Intent();
            string uri = "file://" + requestedUri;
            share.SetData(Android.Net.Uri.Parse(uri));

            // OR
            //Android.Net.Uri uri = Android.Net.Uri.Parse(requestedUri);
            //Intent share = new Intent(Intent.ActionSend);
            //share.PutExtra(Intent.ExtraStream, uri);
            //share.SetType("image/*");
            //share.AddFlags(ActivityFlags.GrantReadUriPermission);

            SetResult(Result.Ok, share);
            Finish();
        });

Above will listen for the message when the image is selected.

Then in XFroms code when image is selected dowload it, store it, get path and send to Activity using it's path. Below is my test path

MessagingCenter.Send<ReturnImagePage, string>(this, "imageUri", "/storage/emulated/0/Android/data/ButtonRendererDemo.Droid/files/Pictures/temp/IMG_20170207_174559_21.jpg");
Yuri S
  • 5,355
  • 1
  • 15
  • 23
  • You are a star, this answer is so far above what the question asked for and solves the problem perfectly, thank you. – Shaine Fisher Jul 14 '17 at 04:25
  • You are welcome. For completeness I would like to mention that you could implement an interface like void ImageSelected(string uri) and using dependency service call it from PCL but that would require to find main activity in implementation to cal functions on it. If anybody strongly doesn't like MesssagingCenter (I know there are such people) interface can be used. – Yuri S Jul 14 '17 at 15:20
  • I will take this code forward with me to my next project, sadly Android.Net have me errors, because I need to upgrade some Nuget packages, and that hasn't gone well. I can't get all projects on the same version and the references don't line up in the Android project and PCL so I end up chasing errors. Looks like things aren't yet perfect, but I'm very impressed with some of the things I have seen. Thanks again for your help. – Shaine Fisher Jul 15 '17 at 09:08
  • I just posted a followup question that you may have a working knowledge of https://stackoverflow.com/questions/45221697/android-post-image-to-facebook-comment if you're around and have a second, please. – Shaine Fisher Jul 20 '17 at 17:43