Xamarin Binding Class - binding

I'm developing an app for iOS using Xamarin.
In my solution i've added a binding project to include some native library, but I've some trouble writing the ApiDefinition.cs
This is the original library:
#class AccordionView;
#protocol AccordionViewDelegate <NSObject>
#optional
- (void)accordion:(AccordionView *)accordion didChangeSelection:(NSIndexSet *)selection;
- (void)accordion:(AccordionView *)accordion heightUpdate:(NSInteger)height;
#end
#interface AccordionView : UIView <UIScrollViewDelegate> {
[..]
}
- (void)addHeader:(id)aHeader withView:(id)aView setBool:(BOOL)arrow;
- (void)setOriginalSize:(CGSize)size forIndex:(NSUInteger)index;
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView;
- (void)touchDown:(id)sender;
This is how i writed the ApiDefinitions.cs
[BaseType (typeof(UIView))]
interface AccordionView : UIScrollViewDelegate
{
[Export ("initWithFrame:")]
IntPtr Constructor(RectangleF frame);
[Export ("addHeader:withView:setBool:")]
void AddHeader(NSObject aHeader, NSObject aView, bool arrow);
[Export ("touchDown:")]
void TouchDown(NSObject sender);
[Export ("setOriginalSize:forIndex:")]
void SetOriginalSize(SizeF size, uint index);
[Export ("scrollViewDidScroll:")]
void ScrollViewDidScroll(UIScrollView scrollView);
}
[BaseType (typeof(NSObject))]
[Model]
interface AccordionViewDelegate
{
[Export ("accordion:didChangeSelection:")]
void DidChangeSelection(AccordionView accordion, NSIndexSet selection);
[Export ("accordion:heightUpdate:")]
void HeightUpdate(AccordionView accordion, int height);
}
My problem is on the UIScrollViewDelegate, I don't know how to "translate" it.
Someone can help me? :)

Have you tried looking at the walk-through using Objective Sharpie?
http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c/Walkthrough_Binding_objective-c_library/

Related

Objective c binding not loading in xamarin forms ios

I am building my first objective c library binding. I am following this documentation from Microsoft. I have successfully created a fat binary from IronSource.framework and have also generated apidefinition and structs using objective sharpie and added my binary to it.
After doing that I added binding library to my xamarin.ios project. when i try to create a new instance of a class from the exposed API I get an error.
The type or namespace name 'IronSource' could not be found (are you missing a using directive or an assembly reference?) Stock.iOS D:\Backup Version for Stock Adviser\Version 1.6\Version code 37\StockAdviserCode\Stock\Stock\Stock.iOS\AdControlViewRenderer.cs
'AdControlViewRenderer.BannerWrapper' does not implement inherited
abstract member
'ISBannerDelegate.DidClickBanner()' Stock.iOS D:\Backup Version for
Stock Adviser\Version 1.6\Version code
37\StockAdviserCode\Stock\Stock\Stock.iOS\AdControlViewRenderer.cs
I think my objective c library and xamarin.ios project are not linking properly
My Binding project name is IronSource and my xamarin forms ios project name is Stock.iOS
//APIDefinition
using System;
using Foundation;
using ObjCRuntime;
using UIKit;
namespace IronSource
{
// #interface ISBannerView : UIView
[BaseType(typeof(UIView))]
interface ISBannerView
{
}
// #protocol ISBannerDelegate <NSObject>
[BaseType(typeof(NSObject))]
[Model]
interface ISBannerDelegate
{
// #required -(void)bannerDidLoad:(ISBannerView *)bannerView;
[Abstract]
[Export("bannerDidLoad:")]
void BannerDidLoad(ISBannerView bannerView);
// #required -(void)bannerDidFailToLoadWithError:(NSError *)error;
[Abstract]
[Export("bannerDidFailToLoadWithError:")]
void BannerDidFailToLoadWithError(NSError error);
// #required -(void)didClickBanner;
[Abstract]
[Export("didClickBanner")]
void DidClickBanner();
// #required -(void)bannerWillPresentScreen;
[Abstract]
[Export("bannerWillPresentScreen")]
void BannerWillPresentScreen();
// #required -(void)bannerDidDismissScreen;
[Abstract]
[Export("bannerDidDismissScreen")]
void BannerDidDismissScreen();
// #required -(void)bannerWillLeaveApplication;
[Abstract]
[Export("bannerWillLeaveApplication")]
void BannerWillLeaveApplication();
}
}
//my xamarin.ios
using System;
using CoreGraphics;
using Foundation;
using Stock.iOS;
using Stock.Services;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using IronSource;
[assembly: ExportRenderer(typeof(AdControlView), typeof(AdControlViewRenderer))]
namespace Stock.iOS
{
public class AdControlViewRenderer : ViewRenderer
{
public AdControlViewRenderer()
{ }
protected AdControlView AdViewControl => (AdControlView)Element;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
return;
IronSource ironSource = new IronSource();
SetNativeControl();
}
private void SetNativeControl()
{
try
{
BannerWrapper bannerWrapper = new BannerWrapper(ViewController);
IronSource.SetBannerDelegate(bannerWrapper);
var bannerSize = new ISBannerSize("BANNER");
IronSource.LoadBannerWithViewController(ViewController, bannerSize);
var adview = bannerWrapper.BannerView();
SetNativeControl(adview);
}
catch (Exception ex)
{
}
}
}
public class BannerWrapper : ISBannerDelegate
{
readonly UIViewController parent;
ISBannerView bannerView = null;
public bool DestroyBanner()
{
if (bannerView != null)
{
IronSource.DestroyBanner(bannerView);
bannerView = null;
return true;
}
return false;
}
public BannerWrapper(UIViewController viewController)
{
this.parent = viewController;
}
public override void BannerDidClick()
{
}
public override void BannerDidDismissScreen()
{
}
public override void BannerDidFailToLoadWithError(NSError error)
{
}
public ISBannerView BannerView()
{
ISBannerView bannerView = new ISBannerView();
nfloat y = this.parent.View.Frame.Size.Height - (bannerView.Frame.Size.Height / 2);
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
y -= this.parent.View.SafeAreaInsets.Bottom;
}
bannerView.Center = new CGPoint(this.parent.View.Frame.Size.Width / 2, y);
return bannerView;
}
public override void BannerDidLoad(ISBannerView bnView)
{
InvokeOnMainThread(() =>
{
bannerView = bnView;
nfloat y = this.parent.View.Frame.Size.Height - (bannerView.Frame.Size.Height / 2);
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
y -= this.parent.View.SafeAreaInsets.Bottom;
}
bannerView.Center = new CGPoint(this.parent.View.Frame.Size.Width / 2, y);
this.parent.View.AddSubview(bannerView);
bannerView.AccessibilityLabel = "bannerContainer";
});
}
public override void BannerWillLeaveApplication()
{
}
public override void BannerWillPresentScreen()
{
}
}
}
Any help is welcome
So, I was able to make it work by adding fat binary to Xamarin.ios and changed the build type from "Do not copy" to "Copy Always" and then added a linker to that fat binary using
-cxx -gcc_flags "-L${ProjectDir} -lIronSource -force_load ${ProjectDir}/IronSource.a
I used this GitHub repo for guidance.
Overall to setup IronSoruce, I had to add dll in references, native framework to native reference, fat binary to projectdir and add linker to fat binary.

How to set request orientation in runtime?

I want my gluon application to be able to change orientation from Landscape to portrait in run time. I have check the Gluon Charmdown SDK, It seem that it have only getOrientation and don't have an option to set an orientation in runtime. I don't want to set fixed orientation in Manifest
Charm Down has an OrientationService, but as you have mentioned, it is "read only", it just listens to orientation changes and gives you the current orientation at any time. But so far you can set the orientation programatically.
To include this feature there are two options: clone Charm Down, modify the Orientation Service, build and use your custom build, or directly create a new service, like ExtendedOrientationService, that you can include in your project directly.
Assuming the latter, this is a very basic implementation of a service that allows setting the orientation programmatically:
ExtendedOrientationService.java
package com.gluonhq.charm.down.plugins;
import javafx.geometry.Orientation;
public interface ExtendedOrientationService {
void coerceOrientation(Orientation orientation);
void releaseOrientation();
}
ExtendedOrientationServiceFactory.java
package com.gluonhq.charm.down.plugins;
import com.gluonhq.charm.down.DefaultServiceFactory;
public class ExtendedOrientationServiceFactory extends DefaultServiceFactory<ExtendedOrientationService> {
public ExtendedOrientationServiceFactory() {
super(ExtendedOrientationService.class);
}
}
For Android:
AndroidExtendedOrientationService.java
package com.gluonhq.charm.down.plugins.android;
import android.content.pm.ActivityInfo;
import com.gluonhq.charm.down.plugins.ExtendedOrientationService;
import javafx.geometry.Orientation;
import javafxports.android.FXActivity;
public class AndroidExtendedOrientationService implements ExtendedOrientationService {
private final FXActivity instance = FXActivity.getInstance();
#Override
public void coerceOrientation(Orientation orientation) {
if (orientation.equals(Orientation.HORIZONTAL)) {
instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else if (orientation.equals(Orientation.VERTICAL)) {
instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
}
#Override
public void releaseOrientation() {
instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
}
On iOS:
ExtendedOrientation.h
#import <UIKit/UIKit.h>
#include "jni.h"
#interface ExtendedOrientation : UIViewController {}
#property (nonatomic, assign) BOOL shouldAutoRotate;
- (void) setOrientation:(NSString *)orientation;
- (void) release;
#end
ExtendedOrientation.m
#include "ExtendedOrientation.h"
extern JNIEnv *jEnv;
#define GET_MAIN_JENV \
if (jEnv == NULL) NSLog(#"ERROR: Java has been detached already, but someone is still trying to use it at %s:%s:%d\n", __FUNCTION__, __FILE__, __LINE__);\
JNIEnv *env = jEnv;
JNIEXPORT jint JNICALL
JNI_OnLoad_ExtendedOrientation(JavaVM *vm, void *reserved)
{
#ifdef JNI_VERSION_1_8
//min. returned JNI_VERSION required by JDK8 for builtin libraries
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
return JNI_VERSION_1_4;
}
return JNI_VERSION_1_8;
#else
return JNI_VERSION_1_4;
#endif
}
static int ExtendedOrientationInited = 0;
// ExtendedOrientation
ExtendedOrientation *_extendedOrientation;
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSExtendedOrientationService_initOrientation
(JNIEnv *env, jclass jClass)
{
if (ExtendedOrientationInited)
{
return;
}
ExtendedOrientationInited = 1;
_extendedOrientation = [[ExtendedOrientation alloc] init];
}
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSExtendedOrientationService_setOrientation
(JNIEnv *env, jclass jClass, jstring jOrientation)
{
const jchar *charsOrientation = (*env)->GetStringChars(env, jOrientation, NULL);
NSString *orientation = [NSString stringWithCharacters:(UniChar *)charsOrientation length:(*env)->GetStringLength(env, jOrientation)];
(*env)->ReleaseStringChars(env, jOrientation, charsOrientation);
[_extendedOrientation setOrientation:orientation];
}
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSExtendedOrientationService_release
(JNIEnv *env, jclass jClass)
{
[_extendedOrientation release];
}
#implementation ExtendedOrientation
-(void) setOrientation:(NSString*)orientation
{
_shouldAutoRotate = YES;
NSLog(#"Set orientation: %#", orientation);
if ([orientation isEqualToString:#"HORIZONTAL"])
{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft] forKey:#"orientation"];
} else
{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInt:UIInterfaceOrientationPortrait] forKey:#"orientation"];
}
}
- (void) release
{
_shouldAutoRotate = NO;
}
- (BOOL)shouldAutorotate
{
return _shouldAutoRotate;
}
#end
IOSExtendedOrientationService.java
package com.gluonhq.charm.down.plugins.ios;
import com.gluonhq.charm.down.plugins.ExtendedOrientationService;
import javafx.geometry.Orientation;
public class IOSExtendedOrientationService implements ExtendedOrientationService {
static {
System.loadLibrary("ExtendedOrientation");
initOrientation();
}
#Override
public void coerceOrientation(Orientation orientation) {
setOrientation(orientation.toString());
}
#Override
public void releaseOrientation() {
release();
}
// native
private static native void initOrientation();
private static native void setOrientation(String orientation);
private static native void release();
}
Now add the ios-gradle.build file from this sample.
Finally we need to build and include the native library:
build.gradle
apply from: 'ios-build.gradle'
task xcodebuild {
doLast {
xcodebuildIOS("$project.buildDir","$project.projectDir", "ExtendedOrientation")
}
}
task installNativeLib (type:Copy, dependsOn: xcodebuild) {
from("$project.buildDir/native")
into("src/ios/jniLibs")
include("*.a")
}
You can build and add the library to the project with:
./gradlew installNativeLib
SAMPLE
This snippet shows how to use this service: If the orientation is vertical it will force horizontal orientation, else it will release the orientation:
Services.get(ExtendedOrientationService.class).ifPresent(o -> {
Orientation orientation = Services.get(OrientationService.class)
.flatMap(OrientationService::getOrientation)
.orElse(Orientation.HORIZONTAL);
if (orientation == Orientation.VERTICAL) {
o.coerceOrientation(Orientation.HORIZONTAL);
} else {
o.releaseOrientation();
}
});

After binding using Objective Sharpie Protocol Methods are not getting invoked in xamarin.iOS

I have few issues with Binding using Objective sharpie.I am binding IndoorAtlas iOS native sdk with Xamarin.ios.
Issue is while Implementing Protocols methods as those are not getting invoked. Do we need to handle it in special way?
I am attaching API defination file and Implementation file.
// #protocol IALocationManagerDelegate
[Protocol, Model]
[BaseType(typeof(NSObject))]
interface IALocationManagerDelegate
{
// #optional -(void)indoorLocationManager:(IALocationManager *
_Nonnull)manager didUpdateLocations:(NSArray * _Nonnull)locations;
[Export("indoorLocationManager:didUpdateLocations:")]
void DidUpdateLocations(IALocationManager manager, IALocation[] locations);
// #optional -(void)indoorLocationManager:(IALocationManager *
_Nonnull)manager didEnterRegion:(IARegion * _Nonnull)region;
[Export("indoorLocationManager:didEnterRegion:")]
void DidEnterRegion(IALocationManager manager, IARegion region);
}
// #interface IALocationManager : NSObject
[BaseType(typeof(NSObject))]
interface IALocationManager
{
[Wrap("WeakDelegate")]
[NullAllowed]
IALocationManagerDelegate Delegate { get; set; }
// #property (readwrite, nonatomic, weak) id<IALocationManagerDelegate>
_Nullable delegate;
[NullAllowed, Export("delegate", ArgumentSemantic.Weak)]
NSObject WeakDelegate { get; set; }
}
////ViewController --Calling delegate methods
[Export("indoorLocationManager:didUpdateLocations:")]
public void DidUpdateLocations(IALocationManager manager , IALocation[] locations)
{
IALocation loc = locations[locations.Length - 1];
if (mFloorPlan != null)
{
CoreGraphics.CGPoint cg = mFloorPlan.CoordinateToPoint(loc.Location.Coordinate);
this.map.Center = cg;
}
}
[Export("indoorLocationManager:didEnterRegion:")]
public void DidEnterRegion(IALocationManager manager, IARegion region)
{
if (region.Type != ia_region_type.FloorPlan)
Console.WriteLine("Region Changed to {0} " + region.Identifier);
else
{
FetchFloorPlan();
}
}
Don't forget to assign the viewcontroller to the weak delegate.
IALocationManager manager = new IALocationManager();
manager.WeakDelegate = this;

public private and protected in objective-c

Hi I am trying to learn Opps concept in Objective C but I know PHP so I took a program in which for public, private and protected mentioned bellow.
<?php
//Public properties and method can be inherited and can be accessed outside the class.
//private properties and method can not be inherited and can not be accessed outside the class.
//protected properties and method can be inherited but can not be accessed outside the class.
class one
{
var $a=20;
private $b=30;
protected $c=40;
}
class two extends one
{
function disp()
{
print $this->c;
echo "<br>";
}
}
$obj2=new two;
$obj2->disp(); //Inheritance
echo"<br>";
$obj1=new one;
print $obj1->c; //Outside the class
?>
So this I am trying to convert in Objective c code mentioned bellow.
#import <Foundation/Foundation.h>
#interface one : NSObject
{
#private int a;
#public int b;
#protected int c;
}
#property int a;
#property int b;
#property int c;
#end
#implementation one
#synthesize a,b,c;
int a=10;
int b=20;
int c=30;
#end
#interface two : one
-(void)setlocation;
#end
#implementation two
-(void)setlocation;
{
// NSLog(#"%d",a);
NSLog(#"%d",b);
// NSLog(#"%d",c);
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
two *newtwo;
newtwo =[[two alloc]init];
//calling function
[newtwo setlocation];
}
return 0;
}
When I run the above code I am getting
2015-11-03 23:20:16.877 Access Specifier[3562:303] 0
Can some one resolve my problem.
This type of question has been asked before and there's a good explanation in the accepted answer for Private ivar in #interface or #implementation
In general I would recommend you avoid instance variables and use #property instead. Properties have the benefit of read-only/write controls, and free synthesized setters and getters (which if you're learning OOP concepts is a critical concept you should employ).
Properties are declared in the #interface part of an Obj-C file. For access control (according to the link) you have no public/private/protected keywords. All Obj-C methods (and by extension, properties) are public if they're defined in the .h file. If you want them "private" you define them in the the .m file using a class category:
//MyClass.m
#interface MyClass ()
#property(nonatomic, retain) NSString* myString;
#end
#implementation MyClass
#end

ASIHTTPRequest Monotouch Binding Callback/Event

I am trying to wrap ASIHTTPRequest objective-c library to monotouch and I am stuck on .
The objective-c header file contains
#property (assign) SEL requestDidFinishSelector;
and when I use monotouch binding generator it generates
[Export ("requestDidStartSelector")]
Selector RequestDidStartSelector { get; set; }
This compiles successfully but it does not get called. I want to be able to do
networkQueue.RequestDidFinish += HandleRequestFinish;
from my C# code.
Does anyone already have ASIHTTPRequest monotouch binding or guide me on how to hook up callback events?
Thanks.
The selector will only return the handle to the "selector" that you can use.
What you need to do is write your event handler more or less like this:
class MyCallbacker {
public MyCallbacker (Action t) { this.t = t; }
[Preserve (Conditional=true)]
[Export ("MyCallBack")]
void Callback () {
t ();
}
}
event RequestDidFinish {
add {
requestDidFinishSelector = new Selector ("MyCallback");
new MyCallbacker (() => value);
}
}

Resources