Xamarin Estimote not finding beacons for iOS - ios

Im just trying to get a really simple POC of my multiplatform app finding ibeacons in a crossplatform xamarin solution. I've got the android side of things going but just hitting issues with the iOS side of things.
I've got the following hacked up code in the AppDelegate class (this is just to first muck around with it, i realize this isnt where it should reside):
[Register("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
static readonly string uuid = "B9407F30-F5F8-466E-AFF9-25556B57FE6D";
static readonly string monkeyId = "Monkey";
CBPeripheralManager peripheralMgr;
BTPeripheralDelegate peripheralDelegate;
CLLocationManager locationMgr;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
myAppManagerApp.Init(typeof(myAppManagerApp).Assembly);
Forms.Init();
// FormsMaps.Init();
UINavigationBar.Appearance.BackgroundColor = UIColor.FromRGBA(0, 0, 0, 0);
UINavigationBar.Appearance.TintColor = UIColor.Blue;
UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes()
{
TextColor = UIColor.White
});
window.RootViewController = BuildView();
window.MakeKeyAndVisible();
var monkeyUUID = new NSUuid(uuid);
var beaconRegion = new CLBeaconRegion(monkeyUUID, monkeyId);
//power - the received signal strength indicator (RSSI) value (measured in decibels) of the beacon from one meter away
var power = new NSNumber(-59);
NSMutableDictionary peripheralData = beaconRegion.GetPeripheralData(power);
peripheralDelegate = new BTPeripheralDelegate();
peripheralMgr = new CBPeripheralManager(peripheralDelegate, DispatchQueue.DefaultGlobalQueue);
peripheralMgr.StartAdvertising(peripheralData);
locationMgr = new CLLocationManager();
locationMgr.RegionEntered += (object sender, CLRegionEventArgs e) =>
{
if (e.Region.Identifier == monkeyId)
{
var notification = new UILocalNotification() { AlertBody = "There's a monkey hiding nearby!" };
UIApplication.SharedApplication.PresentLocationNotificationNow(notification);
}
};
locationMgr.DidStartMonitoringForRegion += locationMgr_DidStartMonitoringForRegion;
locationMgr.MonitoringFailed += locationMgr_MonitoringFailed;
locationMgr.StartMonitoring(beaconRegion);
locationMgr.StartRangingBeacons(beaconRegion);
locationMgr.DidRangeBeacons +=locationMgr_DidRangeBeacons;
return true;
}
private void locationMgr_DidRangeBeacons(object sender, CLRegionBeaconsRangedEventArgs e)
{
throw new NotImplementedException();
}
private void locationMgr_MonitoringFailed(object sender, CLRegionErrorEventArgs e)
{
throw new NotImplementedException();
}
private void locationMgr_DidStartMonitoringForRegion(object sender, CLRegionEventArgs e)
{
int i = 0;
//throw new NotImplementedException();
}
static UIViewController BuildView()
{
var root = new pgeRoot();
var controller = root.CreateViewController();
return controller;
}
Ive chopped most of the code out of the Find the monkey sample. Either way the DidRangeBeacons or RegionEntered events never fire. I'm using estimote iBeacons so i dont know whether that makes a difference?
Any ideas on what im missing here? Is there a permission or setting i need to put into the plist?
Thanks

In iOS 8 you need to explicitly ask for permission to use Location Services - it's the CLLocationManager's RequestAlwaysAuthorization (for monitoring) and RequestWhenInUseAuthorization (for ranging) methods. You also need an appropriate (NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription) entry in the Info.plist file of your iOS app, though I'm not entirely surely how to do this in Xamarin.

Related

How do you send message using NFC with Xamarin.Android?

I am developing and app to demostrate how NFC works. My goal is to make and app that will work very similary to Android Beam. I am using Xamarin.Android. The goal is to type message to one device, press button and it should be send to another device with the same app where it should be shown. I have tried almost everything even the documentation but it seems like it doesnt work. Does anyone have any experience with this technology? Is this technology even available nowadays?
There is some of my code to get you an idea about what i am trying to do:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
mNfcAdapter = NfcAdapter.GetDefaultAdapter(this);
myButton.Click += (e, o) => {
mNfcAdapter.SetNdefPushMessageCallback(this, this);
mNfcAdapter.SetOnNdefPushCompleteCallback(this, this);
};
}
public NdefMessage CreateNdefMessage(NfcEvent e)
{
DateTime time = DateTime.Now;
var text = (time.ToString("HH:mm:ss") + message2);
NdefMessage msg = new NdefMessage(
new NdefRecord[] { CreateMimeRecord (
text, Encoding.UTF8.GetBytes (text))});
return msg;
}
private NdefRecord CreateMimeRecord(string mimeType, byte[] payload)
{
byte[] mimeBytes = Encoding.UTF8.GetBytes(mimeType);
NdefRecord mimeRecord = new NdefRecord(
NdefRecord.TnfMimeMedia, mimeBytes, new byte[0], payload);
return mimeRecord;
}
public void OnNdefPushComplete(NfcEvent e)
{
Toast.MakeText(this.ApplicationContext, "Message sent", ToastLength.Long).Show();
}
protected override void OnResume()
{
base.OnResume();
if (NfcAdapter.ActionNdefDiscovered == Intent.Action)
{
ProcessIntent(Intent);
}
}
protected override void OnNewIntent(Intent intent)
{
Intent = intent;
}
void ProcessIntent(Intent intent)
{
IParcelable[] rawMsgs = intent.GetParcelableArrayExtra(
NfcAdapter.ExtraNdefMessages);
NdefMessage msg = (NdefMessage)rawMsgs[0];
var textViewMsg = FindViewById<TextView>(Resource.Id.textViewMsg);
textViewMsg.Text = Encoding.UTF8.GetString(msg.GetRecords()[0].GetPayload());
}
Thank you all :)
OnNdefPushComplete and the whole Android Beam was deprecated and removed from Android 10
https://developer.android.com/reference/android/nfc/NfcAdapter.OnNdefPushCompleteCallback
If you want to do Device to Device NFC going forward then it should be possible with one phone doing Host Card Emulation (HCE) and the other using enableReaderMode
But Google recommend using Bluetooth or Wifi Direct as a more reliable replacement for Android Beam. One of the replacement methods Google provided was Android Nearby https://developers.google.com/nearby

Auto OTP verification android xamarin

I am working on an Android App using Xamarin, in which server sends an OTP and the user needs to enter this OTP in the App, to SignUp for my App. What I want is, that my App should be able to automatically read the OTP sent by the server and to be filled in edit text field of OTP.
I'm almost done to read the message but unable to set the otp in edit text field.
SMS broadcast receiver class:
[BroadcastReceiver(Enabled = true, Label = "SMS Receiver")]
[IntentFilter(new string[] { "android.provider.Telephony.SMS_RECEIVED" })]
public class SMSBroadcastReceiver : BroadcastReceiver
{
private const string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
public override void OnReceive(Context context, Intent intent)
{
try
{
if (intent.Action != IntentAction) return;
var bundle = intent.Extras;
if (bundle == null) return;
var pdus = bundle.Get("pdus");
// var castedPdus = JNIEnv.GetArray(pdus.Handle);
var castedPdus = JNIEnv.GetArray<Java.Lang.Object>(pdus.Handle);
var msgs = new SmsMessage[castedPdus.Length];
var sb = new StringBuilder();
string sender = null;
for (var i = 0; i < msgs.Length; i++)
{
var bytes = new byte[JNIEnv.GetArrayLength(castedPdus[i].Handle)];
JNIEnv.CopyArray(castedPdus[i].Handle, bytes);
string format = bundle.GetString("format");
msgs[i] = SmsMessage.CreateFromPdu(bytes,format);
if (sender == null)
sender = msgs[i].OriginatingAddress;
sb.Append(string.Format("SMS From: {0}{1}Body: {2}{1}", msgs[i].OriginatingAddress,System.Environment.NewLine, msgs[i].MessageBody));
Toast.MakeText(context, sb.ToString(), ToastLength.Long).Show();
}
}
catch (System.Exception ex)
{
Toast.MakeText(context, ex.Message, ToastLength.Long).Show();
}
}
}
Here is my main activity:
[Activity(Label = "UserSms", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
SMSBroadcastReceiver smsReceiver = new SMSBroadcastReceiver();
TextView msg = FindViewById<TextView>(Resource.Id.editTextOtp);
Button btn = FindViewById<Button>(Resource.Id.button3);
RegisterReceiver(smsReceiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
}
}
How can I achieve this? Any help or guidance in this regard would be highly appreciated.
Update
public void onSMSReceived(string msgs)
{
EditText OtpNumber = (EditText)FindViewById(Resource.Id.editTextOtp);
try
{
OtpNumber.SetText(msgs.ToString(),null);
}
catch (System.Exception ex)
{
}
}
Your are on the finishing line. You only need to do these thing:
Create an interface which will have public method onSMSReceived(String smsMsg)
Instantiate that interface.
Implement that interface in MainActivity activity.
Override onSMSReceived(String smsMsg) in your MainActivity
Notify MainActivity using above created interface from your SMS Broadcast Receiver.
Populate message received in onSMSReceived(String smsMsg) in your MainActivity.
You are done.
I didn't get exactly how you're doing it, but i did in two ways,
1.User has to enter it manually,
2.We have to read automatically through the programming,
But i faced one problem in reading sms automatically, like sending sms and reading sms are calling at the same time may be like register click event, I found one more way to detect automatically like sending otps two times and storing generated otps in a list of string and comparing with message.body
Here the problem is we have to send otp two times, still i'm figuring out how to call reading sms part after sometime,,,!
If you want that solution plz mail me at sailokeshgoud#gmail.com

iOS: Camera does not recognize QR Code on first load of view controller

I have a small app, that does read QR-Codes for a login and alternatively offers the possibility to hand-type the code and login.
The app starts and heads directly to the login (View). When I try to scan a qr code that does not work - the delegate is never called/the event never raised.
I adapted the approach from Larry OBrien http://www.knowing.net/index.php/2013/10/09/natively-recognize-barcodesqr-codes-in-ios-7-with-xamarin-ios/
And created my own ScannerView class for that use:
public sealed partial class ScannerView : UIView
{
private readonly AVCaptureVideoPreviewLayer _layer;
public AVCaptureSession Session { get; }
private readonly AVCaptureMetadataOutput _metadataOutput;
public event EventHandler<AVMetadataMachineReadableCodeObject> MetadataFound = delegate { };
public ScannerView (IntPtr handle) : base (handle)
{
Session = new AVCaptureSession();
var camera = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video);
var input = AVCaptureDeviceInput.FromDevice(camera);
Session.AddInput(input);
//Add the metadata output channel
_metadataOutput = new AVCaptureMetadataOutput {RectOfInterest = Bounds};
var metadataDelegate = new MetadataOutputDelegate();
var dispatchQueue = new DispatchQueue("scannerQueue");
_metadataOutput.SetDelegate(metadataDelegate, dispatchQueue);
Session.AddOutput(_metadataOutput);
_layer = new AVCaptureVideoPreviewLayer(Session)
{
MasksToBounds = true,
VideoGravity = AVLayerVideoGravity.ResizeAspectFill,
Frame = Bounds
};
Layer.AddSublayer(_layer);
// Hand event over to subscriber
metadataDelegate.MetadataFound += (s, e) => MetadataFound(s, e);
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
_layer.Frame = Bounds;
_metadataOutput.RectOfInterest = Bounds;
}
public void SetMetadataType(AVMetadataObjectType type)
{
//Confusing! *After* adding to session, tell output what to recognize...
_metadataOutput.MetadataObjectTypes = type;
}
}
And in my LoginView I do the following:
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
// Manipulate navigation stack
NavigationController.SetViewControllers(
NavigationController.ViewControllers.Where(
viewController => viewController is LoginView).ToArray(), false);
ScannerView.MetadataFound += (s, e) =>
{
Console.WriteLine($"Found: [{e.Type.ToString()}] {e.StringValue}");
LoginViewModel.BarCode = e.StringValue;
if (LoginViewModel.DoneCommand.CanExecute())
{
ScannerView.Session.StopRunning();
LoginViewModel.DoneCommand.Execute();
}
};
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
ScannerView.Session.StartRunning();
ScannerView.SetMetadataType(AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code);
}
Funny thing is, that this works once I logged in with the manual input and logged out again, so I'm on the same screen again (possibly not the same but a new instance of it as the GC may destroy the view as it is removed from the navigation stack?)
I have put the scannerview as a subview on the LoginView in the storyboard. For navigation I use MVVMCross. (just for info)
So: What am I doing wrong? What do I need to do to make it work on the first load? (I got it to do that once - with the same code... maybe it is a timing issue?)
Obviously this is a timing issue.
I solved it by adding a "Tap to scan" paradigm.
When tapping I execute the following code:
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
Console.WriteLine($"Current types to scan: {this.MetadataOutput.MetadataObjectTypes}");
this.SetMetadataType(this.MetadataObjectType);
Console.WriteLine($"New types to scan: {this.MetadataOutput.MetadataObjectTypes}");
}
public void SetMetadataType(AVMetadataObjectType type)
{
//Confusing! *After* adding to session, tell output what to recognize...
this.Session.BeginConfiguration();
this.MetadataOutput.MetadataObjectTypes = type;
this.Session.CommitConfiguration();
}
Where MetadataObjectType is set to the codes we're looking for before.
And that solves the problem - the scanning now works every time.
I think the magic part is the Begin- and CommitConfiguration call, as this also works, if I do not use the touch to scan paradigm.

Bring application from background to foreground while receiving incoming call via BroadcastReceiver

I am developing an cross platform application using Xamarin, for SIP calling. I have incoming and outgoing calls working.
Although, I have a problem with receiving call in when the App is running in the background.
I have tried to bring application to front, when a call is received. The code I have used follows:
In my MainActivity
private void registerReceiver()
{
IncomingCallReceiver callReceiver = new IncomingCallReceiver();
IntentFilter sipIntentFilter = new IntentFilter();
sipIntentFilter.AddAction("com.NelsonApp.INCOMING_CALL");
this.RegisterReceiver(callReceiver, sipIntentFilter);
}
and in my BroadcastReceiver
public override void OnReceive(Context context, Intent intent)
{
DialerCallListener listener = new DialerCallListener();
SIPRegistration.call = SIPRegistration.sipManager.TakeAudioCall(intent, listener);
string str = SIPRegistration.call.PeerProfile.UriString;
char [] strArray = {':','#'};
var value = str.Split(strArray)[1];
Intent newIntent = new Intent(context, typeof(MainActivity));
newIntent.AddFlags(ActivityFlags.FromBackground);
newIntent.AddCategory(Intent.CategoryLauncher);
context.StartActivity(newIntent);
PlaySound myActivity = new PlaySound();
myActivity.PlayRingtone(context);
MainActivity.isIncomingCall = true;
MessagingCenter.Send(string.Empty, "IncomingCall", value);
}
I tried with different ActivityFlags like NewTask, SingleTop, ReorderToFront, ReceiverForeground, FromBackground, BroughtToFront. However, noting will bring my app to the foreground.
What else can I do from here?
I have tried following this Link. Although it didn't help.
var intent = new Intent(context, typeof (MainActivity));
intent.AddFlags(ActivityFlags.NewTask);
context.StartActivity(intent);
Should launch your App just fine.
Are you sure your BroadcastReceiver is called?

Location-tracking app suspends in background after few minutes

I try to create a location-tracking app. App should work in background. So, I switch on properties "Enable background modes", "location updates" and added parameter "NSLocationAlwaysUsageDescription" to the source.
On ios7 app works fine, but on ios8 it suspends in background after few minutes (How app should work: I send a request every time when new location is received, and if I can see this request on the server it means that app is working).
I downloaded xamarin.mobile component with location functionality and used it instead of my class for geolocation. App also suspends in the background.
I created Objective-C app with the same functionality and tested it on the same device. Result - app works fine (as expected).
So, maybe app still needs some setting or I'm missing something?
public class LocationUpdatedEventArgs : EventArgs
{
CLLocation location;
public LocationUpdatedEventArgs(CLLocation location)
{
this.location = location;
}
public CLLocation Location
{
get { return location; }
}
}
protected CLLocationManager locMgr;
public event EventHandler<LocationUpdatedEventArgs> LocationUpdated = delegate { };
public GeoLocationService_iOS()
{
this.locMgr = new CLLocationManager();
LocationUpdated += SaveLocation;
locMgr.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs e) =>
{
//CheckStatus();
};
if (locMgr.RespondsToSelector(new Selector("requestAlwaysAuthorization")))
{
locMgr.RequestAlwaysAuthorization();
}
locMgr.DistanceFilter = 1;
locMgr.DesiredAccuracy = CLLocation.AccuracyBest;
locMgr.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) =>
{
// fire our custom Location Updated event
this.LocationUpdated(this, new LocationUpdatedEventArgs(e.Locations[e.Locations.Length - 1]));
};
locMgr.StartUpdatingLocation();
}
public void SaveLocation(object sender, LocationUpdatedEventArgs e)
{
SendLoc();
}
Adding
locMgr.PausesLocationUpdatesAutomatically = false;
solved my problem.

Resources