Start a new topic
Solved

Call C# Xamarin.android method from JavaScript AR world

Hi everyone,


I am trying to call Xamarin.android C# method from JavaScript code when button is pressed. I saw that I have to use following architectsdk protocol to call the c# method. 

document.location = ""architectsdk://"classandmethodnamehere"?param1=" + encodeURIComponent(param1);


However I don't have clue on how to identify the C# method with its class and how to receive the call from JavaScript in c#.The propose of this call to C# is that I want to get an photo from the camera when button is clicked from wikitude. Any help regarding this issue would be highly appreciated since I have been stuck on this issue for more than 7 hours.  


The eventhandler solution wasn't working for us. Also, when we tried the delegate way, we had to instantiate the delegate in the field rather than in the iOS lifecycle. Hopefully this helps someone.

Thank, Daniel.  I got it working using an EventHandler, but I'll try this later.  If this were my thread, I'd mark it as approved - sorry I took the easy way out and hijacked this one!

Hi Jonathan,



sine you should have a class deriving from WTArchitectViewDelegate now which is created inside of your view controller, you should, for example, be able to pass a reference to the delegate class upon creation.


I have something like the following in mind.



public partial class ExampleArchitectViewDelegate : WTArchitectViewDelegate 
{
    private WikitudeSDKExampleViewController _viewController;

    public ExampleArchitectViewDelegate(WikitudeSDKExampleViewController viewController_)
    {
        _viewController = viewController_;
    }

    public override void ReceivedJSONObject(WTArchitectView architectView, NSDictionary jsonObject)
    {
        // pass your data by calling a public method on the view controller
        _viewController.foo(jsonObject);
    }
}

public partial class WikitudeSDKExampleViewController : UIViewController
{
    private ExampleArchitectViewDelegate _architectViewDelegate = new ExampleArchitectViewDelegate(this);
    
    public void foo(NSDictionary jsonObject)
    {
        // do something with jsonObject
    }
    
    [...]
}



Note that haven't tried this, so it might contain errors. But the overall approach seems sound to me.



- Daniel


1 person likes this

Okay, I didn't understand the point of delegates, obviously.  I now am receiving events in my delegate, but I'm unsure how to send that into into my view controller.  

Thanks Daniel.  Maybe you can clarify something for me.  We were previously using WTArchitectView as the view controller for our wikitude AR outlet, but your reference inheriting from WTArchitectViewDelegate.  WTArchitectViewDelegate looks to be is missing (according to my IDE) some functionality we were using, like SetLicenseKey, LoadArchitectWorldFromURL, CallJavaScript.  Any idea what I'm doing wrong?  Here's a code sample:

The controller for this view calls this functionality on ViewDidLoad.  

            NSError error;

            if (WTArchitectView.IsDeviceSupportedForRequiredFeatures(WTFeatures.Geo, out error))
            {
                arView.SetLicenseKey("...");
                var url = NSBundle.MainBundle.BundleUrl.AbsoluteString + "cb-ar-world/index.html";
                architectWorldNavigation = arView.LoadArchitectWorldFromURL(new NSUrl(url), WTFeatures.Geo);

                var wikiPositions = Newtonsoft.Json.JsonConvert.SerializeObject(GetWikitudePOIs()).ToString();
                Console.WriteLine("\nSERIALZED: " + wikiPositions);

                arView.CallJavaScript("World.loadPoisFromJsonData(" + wikiPositions + ");");

                arView.ReceivedJSONObject += (sender, args) => {
                    Console.WriteLine("\nRECEIVED: " + sender);
                    Console.WriteLine("\nRECEIVED: " + args);
                };
            }
            else
            {
                Console.WriteLine("Wikitude feature not supported");
                //Integrate functionality to hanle this scenario
            }


arView is in the designer file as such 

 

		[Outlet]
		Wikitude.Architect.WTArchitectView arView { get; set; } 

 

That outlet just points to a sub view.


So, when I switch arView to be of a Delegate subclass like your example, I lose some of those functional references.  


Thanks.

Good morning Jonathan,



we're definitley in the same boat; C# is not exactly my area of expertise. Having said that, the following two approaches worked for me.


#1


 public partial class ExampleArchitectViewDelegate : WTArchitectViewDelegate 
 {
     public override void ReceivedJSONObject(WTArchitectView architectView, NSDictionary jsonObject)
     {
          Console.WriteLine("ReceivedJSONObject");
     }
 }


#2


 public override void ViewDidLoad ()
 {
     architectView.ReceivedJSONObject += (object sender, ArchitectViewReceivedJSONObjectEventArgs args) =>
     {
         Console.WriteLine("ReceivedJSONObject");
     };
 }



Here's the JavaScript code is used to test it.


AR.context.onScreenClick = function() {
    AR.platform.sendJSONObject({"hello""world"});
};



One thing to be aware of which caught me off guard: release builds (using Xamarin Studio and running on devices at least) does seem to cause Console.WriteLine() to be omitted from the application output window. Also, the debugger will ignore your breakpoints.



- Daniel


Hi, just wanted to hijack this thread to see if there's a quick answer to a related issue.  I'm having trouble getting the ReceivedJSONObject to register properly.  Here's the code - can you spot an obvious issue?  I'm not typically a C# dev, so this is a little confusing for me.

                arView.ReceivedJSONObject += (sender, args) => {
                    Console.WriteLine("\nRECEIVED: " + sender);
                    Console.WriteLine("\nRECEIVED: " + args);
                };

 

FWIW, I'm inserting data just fine into the World, I'm just hung on having it return on click events.  I've also called a dummy function on POI clicks, like so:


  

Marker.prototype.setSelected = function(marker) {
     AR.platform.sendJSONObject({test: 1, test2: 2});

....
}

  

Thanks

Good morning,



I believe it should work pretty much exactly like the snippet you have posted, you'd just need to translate it into C#.


The ArchitectView for Xamarin.Android should have a method called captureScreen with the exact parameters indicated by your snippet and the documentation I linked previously.

 

The Xamarin component, at least to my understanding, ist just a C# wrapper for the Objective C and Java functions of the Wikitude SDK, which is why the regular Android and iOS documentation thereof applies.



- Daniel

Hey Daniel,


Kind of .I am wondering is there anyway to get a snapshot using code like following code with C# Xamarin.Android from WikitudeActivity class of the image on target example ? 


  

SampleCamActivity.this.architectView.captureScreen(ArchitectView.CaptureScreenCallback.CAPTURE_MODE_CAM_AND_WEBVIEW, new CaptureScreenCallback() {
						
						@Override
						public void onScreenCaptured(final Bitmap screenCapture) {
							if ( ContextCompat.checkSelfPermission(SampleCamActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
                                SampleCamActivity.this.screenCapture = screenCapture;
                                ActivityCompat.requestPermissions(SampleCamActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WIKITUDE_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);
                            } else {
                                SampleCamActivity.this.saveScreenCaptureToExternalStorage(screenCapture);
                            }
						}
					});

 

Thank you.


Good morning,



will this be sufficient?


iOS

Android



- Daniel

Hi Daniel,


I Managed to call JavaScript to native code using  AR.platform.sendJSONObject method, However now I am stuck on how to take snapshot from camera using native code. So I am wondering if there is any method in native code that I can used for taking a snapshot?

Hi,



the corresponding C# function of document.location is invokedURL. Within invokedURL you need to parse the url you're given and act based on that.


invokedURL (iOS)

invokedURL (Android)


There is, however, another and arguably easier way of communicating with C# from JavaScript. Instead of document.location and invokedURL you can use AR.platform.sendJSONObject and receivedJSONObject.


sendJSONObject (JS)

receivedJSONObject (iOS)

receivedJSONObject (Android)


- Daniel


Login or Signup to post a comment