xamarin ios app crashing with CBCentralManager - xamarin.ios

I have a Fresh application with basically no code added to it except the following Code.
If I try it in a simulator it goes into update state and says unsupported.
If I try to run in on a 6 generation ipad (with bluetooth turned on) the application crashes as soon as debugging exits UIButton231_TouchUpInside (and never goes into the catch).
Am I missing anything?
CBCentralManager _central;
partial void UIButton231_TouchUpInside(UIButton sender)
{
try
{
BluetoothLEManager();
}
catch (Exception e)
{
Console.Write(e);
}
}
protected void BluetoothLEManager()
{
try
{
_central = new CBCentralManager(DispatchQueue.CurrentQueue);
_central.DiscoveredPeripheral += (object sender, CBDiscoveredPeripheralEventArgs e) =>
{
Console.WriteLine("DiscoveredPeripheral: " + e.Peripheral.Name);
Console.WriteLine("RSSI: " + e.Peripheral.RSSI);
};
_central.UpdatedState += (object sender, EventArgs e) =>
{
Console.WriteLine("UpdatedState: " + _central.State);
};
_central.ConnectedPeripheral += (object sender, CBPeripheralEventArgs e) =>
{
Console.WriteLine("ConnectedPeripheral: " + e.Peripheral.Name);
};
_central.DisconnectedPeripheral += (object sender, CBPeripheralErrorEventArgs e) =>
{
Console.WriteLine("DisconnectedPeripheral: " + e.Peripheral.Name);
};
}
catch (Exception e)
{
Console.Write(e);
}
}
In the Image below (code is compacted to make the image shorter), debugging reaches line 62 just fine, but attempting to step over or to just let it continue will close the application, and breakpoints in the catch are not reached.

I have tried shared code in local site , and it also crashes and with some error logs :
After checking this line error :
Got a SIGABRT while executing native code. This usually indicates a fatal error in the mono runtime or one of the native libraries used by your application.
Sometimes that may be caused by permission in iOS . You can have a look at this aticle by James : New iOS 10 Privacy Permission Settings .
Starting in iOS 10, nearly all APIs that require requesting authorization and other APIs, such as opening the camera or photo gallery, require a new key value pair to describe their usage in the Info.plist.
However , in info.plist , you can add the permission of Bluetooth easily as follow and will forget another most important permission :
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Add BlueTooth Peripheral Permission</string>
That's not enough for Bluetooth . You also need to add another permission :
<key>NSBluetoothAlwaysUsageDescription</key>
<string>use Bluetooth</string>
From native info.plist , you also will find it .
This permission is fundamental and necessary . Because this will pop up a permission Dialog window in iOS device .
By the way , there is an offical API about using Bluetooth in Xamarin iOS you can have a look .
public class MySimpleCBCentralManagerDelegate : CBCentralManagerDelegate
{
override public void UpdatedState (CBCentralManager mgr)
{
if (mgr.State == CBCentralManagerState.PoweredOn) {
//Passing in null scans for all peripherals. Peripherals can be targeted by using CBUIIDs
CBUUID[] cbuuids = null;
mgr.ScanForPeripherals (cbuuids); //Initiates async calls of DiscoveredPeripheral
//Timeout after 30 seconds
var timer = new Timer (30 * 1000);
timer.Elapsed += (sender, e) => mgr.StopScan();
} else {
//Invalid state -- Bluetooth powered down, unavailable, etc.
System.Console.WriteLine ("Bluetooth is not available");
}
}
public override void DiscoveredPeripheral (CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
Console.WriteLine ("Discovered {0}, data {1}, RSSI {2}", peripheral.Name, advertisementData, RSSI);
}
}
public partial class HelloBluetoothCSharpViewController : UIViewController
{
MySimpleCBCentralManagerDelegate myDel;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//Important to retain reference, else will be GC'ed
myDel = new MySimpleCBCentralManagerDelegate ();
var myMgr = new CBCentralManager (myDel, DispatchQueue.CurrentQueue);
}

Related

Downloads with JavaFX WebView

my web application offers a download. Javascript creats at the click the url (it depends on the user input) and the browser should open it, so that the page isn't reloaded.
For that, I think I have to alternatives:
// Alt1:
window.open(pathToFile);
// Alt2:
var downloadFrame = document.getElementById('downloads');
if (downloadFrame === null) {
downloadFrame = document.createElement('iframe');
downloadFrame.id = 'downloads';
downloadFrame.style.display = 'none';
document.body.appendChild(downloadFrame);
}
downloadFrame.src = pathToFile;
Both works under Firefox. Problem with open new window method: If the creation of the file at the server needs more time, the new empty tab will be closed late.
Problem with iframe: If there is an error at the server, no feedback is given.
I think at firefox the iframe is the better solution. But the web application must run with an JavaFX WebView, too. JavaFX haven't a download feature, I have to write it. One possible way is to listen on the location property:
final WebView webView = new WebView();
webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue<? extends String> observableValue, String oldLoc, String newLoc) {
if (newLoc.cotains("/download")) {
FileChooser chooser = new FileChooser();
chooser.setTitle("Save " + newLoc);
File saveFile = chooser.showSaveDialog(webView.getEngine().getScene().getWindow());
if (saveFile != null) {
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(new URL(newLoc).openStream());
os = new BufferedOutputStream(new FileOutputStream(saveFile));
while ((readBytes = is.read()) != -1) {
os.write(b);
}
} finally {
try { if (is != null) is.close(); } catch (IOException e) {}
try { if (os != null) os.close(); } catch (IOException e) {}
}
}
}
}
}
There are some problems:
The download start depends on a part of the url, because JafaFX supports no access to the http headers (that is bearable)
If the user starts the download with the same url two times, only the first download works (the change event only fires, if the url is new). I can crate unique urls (with #1, #2 and so on at the end). But this is ugly.
Only the "window.open(pathToFile);" method works. Loading an iframe don't fire the change location event of the website. That is expectable but I haven't found the right Listener.
Can someone help me to solve 2. or 3.?
Thank you!
PS: Sorry for my bad english.
edit:
For 2. I found a way. I don't know if it is a good one, if it is performant, if the new webview is deleted or is in the cache after download, ....
And the user don't get an feedback, when some a problem is raised:
webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
#Override public WebEngine call(PopupFeatures config) {
final WebView downloader = new WebView();
downloader.getEngine().locationProperty().addListener(/* The Listener from above */);
return downloader.getEngine();
}
}
I think you may just need to use copyURLtoFile to get the file...call that when the location changes or just call that using a registered java class. Something like this:
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
Using copyURLToFile the current page doesn't have to serve the file. I think registering the class is probably the easiest way to go... something like this:
PHP Code:
Download $filename
Java (in-line class in your javafx class/window... in this case my javafx window is inside of a jframe):
public class JavaApp {
JFrame cloudFrameREF;
JavaApp(JFrame cloudFrameREF)
{
this.cloudFrameREF = cloudFrameREF;
}
public void getfile(String filename) {
String newLoc = "http://your_web_site.com/send_file.php?filename=" + filename;
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
}
}
This part would go in the main javafx class:
Platform.runLater(new Runnable() {
#Override
public void run() {
browser2 = new WebView();
webEngine = browser2.getEngine();
appREF = new JavaApp(cloudFrame);
webEngine.getLoadWorker().stateProperty().addListener(
new ChangeListener<State>() {
#Override public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
JSObject win
= (JSObject) webEngine.executeScript("window");
// this next line registers the JavaApp class with the page... you can then call it from javascript using "app.method_name".
win.setMember("app", appREF);
}
}
});
You may not need the frame reference... I was hacking some of my own code to test this out and the ref was useful for other things...

Issue with Game Center on Monotouch

I'm trying to implement Game Center into my game but i have problems with it.
Here is my Main.cs code :
namespace iosgame
{
public class Application
{
[Register ("AppDelegate")]
public partial class AppDelegate : IOSApplication {
MainViewController mainViewController;
public AppDelegate(): base(new Game(new StaticsDatabase(),new StoreDatabase(),new InappPurchase(),new Social(),new MissionsDatabase()), getConfig()) {
}
internal static IOSApplicationConfiguration getConfig() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.orientationLandscape = true;
config.orientationPortrait = false;
config.useAccelerometer = false;
config.useMonotouchOpenTK = true;
config.useObjectAL = true;
return config;
}
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
base.FinishedLaunching(app,options);
UIViewController controller = ((IOSApplication)Gdx.app).getUIViewController();
mainViewController = new MainViewController();
controller.View.Add(mainViewController.View);
return true;
}
private bool isGameCenterAPIAvailable()
{
return UIDevice.CurrentDevice.CheckSystemVersion (4, 1);
}
}
static void Main (string[] args)
{
UIApplication.Main (args, null, "AppDelegate");
}
}
}
And here is the superclass of that Main.cs : https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-iosmonotouch/src/com/badlogic/gdx/backends/ios/IOSApplication.java
I'm trying to use this https://github.com/xamarin/monotouch-samples/blob/master/GameCenterSample/GameCenterSample/MainViewController.cs example but i can't see any authenticate window in my game.I can see "Welcome back ,name" notification but after i log out from gamecenter app and reopen my game but i can't see any authentication window.
How can i fix it?
Thanks in advance
Just call this in FinishedLaunching:
if (!GKLocalPlayer.LocalPlayer.Authenticated) {
GKLocalPlayer.LocalPlayer.Authenticate (error => {
if (error != null)
Console.WriteLine("Error: " + error.LocalizedDescription);
});
}
This should display a Game Center "toast" saying "Welcome back, Player 1".
Here are some ideas if this doesn't work:
Make sure you have setup a new bundle id in the developer portal, and declare it in your Info.plist
Start filling out your app details in iTunes connect (Minimum is description, keywords, icon, 1 screenshot), and make sure to enable Game Center and add your new game to a group
Login with a test iTunes user in Game Center (create in ITC), or the login associated with your developer account
PS - I wouldn't worry about checking for iOS 4.1, just target iOS 5.0 and higher these days.

Midlet crashes when calling bluetooth API

When I run following code on my phone I get black screen saying there was uncaught exception but whole block is wrapped in try/catch block so it is weird, anyway when I proceed with execution code just gets to "Getting device.." so it obviously fails on this line:
LocalDevice local = LocalDevice.getLocalDevice();
Here is whole method:
public void startBT()
{
try
{
f.append("Getting device..");
LocalDevice local = LocalDevice.getLocalDevice();
f.append("Got local device..");
DiscoveryAgent agent = local.getDiscoveryAgent();
f.append("Got local discovery agent..");
connString = agent.selectService(new UUID(
"86b4d249fb8844d6a756ec265dd1f6a3", false),
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
f.append("Got connection string - >" + connString);
}
catch (Exception ex)
{
Alert message = new Alert("info");
message.setString(ex.getMessage());
Display.getDisplay(this).setCurrent(message);
}
}
Any ideas?
It looks like device I used doesn't support JSR-82 which is J2ME Bluetooth API(this is built into phone, no way of "installing" it) required to use Bluetooth from J2ME Midlets,here is snippet which should check for JSR-82 support:
public static boolean IsBtJsrComaptible() {
try {
Class.forName("javax.bluetooth.LocalDevice");
return true;
} catch (Exception e) {
return false;
}
}
Please note that I got uncaught exception trying to run above snippet, but maybe it would work on some other device.

What is the best place to detect user sign in when using azure acs and mvc3?

I want to be able to detect when a user signs on to my application using passive acs, so that I can add them to my database if this is the first time using my app. Right now I am subscribing to WSFederationAuthenticationModule.SignedIn but I feel I'm missing something. Mainly I'm not sure the best place to subscribe to the event, I got it to work inside PostAuthenticateRequest but its a bit hacky. Any suggestions?
this code is from global.asax
public override void Init()
{
base.Init();
PostAuthenticateRequest += (s, e) =>
{
try
{
FederatedAuthentication.WSFederationAuthenticationModule.SignedIn -= SignedIn;
}
finally
{
FederatedAuthentication.WSFederationAuthenticationModule.SignedIn += SignedIn;
}
};
}
private void SignedIn(object sender, EventArgs e)
{
//do something
}
EDIT:
For now I'm going to use a flag variable to make sure I only subscribe once to SignedIn. Unless someone has any other suggestions that is :) thanks for the help Sandrino. Here is what I have at the moment.
private static bool isFirstRequest = true;
public override void Init()
{
base.Init();
PostAuthenticateRequest += (s, e) => {
if (isFirstRequest)
{
FederatedAuthentication
.WSFederationAuthenticationModule.SignedIn += SignedIn;
isFirstRequest = false;
}
};
}
private void SignedIn(object sender, EventArgs e)
{
//do something
}
EDIT:
A little more info. This problem happens if I'm using the azure emulator, it probably happens when deployed as well but I haven't tried that. I have tested if I am just not able to debug by trying to write to a text file and no text file was created.
Why do you subscribe to the SignedIn event each time the PostAuthenticateRequest event is raised? You can simple subscribe to it when the application starts (in the Global.asax) and it will be raised for each user that signed in:
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_Start()
{
...
FederatedAuthentication.ServiceConfigurationCreated += (s, e) =>
{
FederatedAuthentication.WSFederationAuthenticationModule.SignedIn += new EventHandler(OnUserSignedIn);
};
}
private void OnUserSignedIn(object sender, EventArgs e)
{
// Custom logic here.
}
}
The SignedIn event is the best way to detect a user sign in before the application continues. Take a look at the following diagram. Before redirecting back to a page, the SignedIn event is raised to allow you to detect an user sign in:
Reference: http://msdn.microsoft.com/en-us/library/ee517293.aspx
I created a class that derives from ClaimsAuthenticationManager. There is only one method that you have to override, which is
public virtual IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal);
In my app, I use this method to check if the user, who has successfully authenticated, is really a user of my app (i.e. they exist in my database). If not, I direct them to a signup page.
My class looks something like this:
public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal.Identity.IsAuthenticated)
{
var identity = incomingPrincipal.Identity as IClaimsIdentity;
User user = null;
// Get name identifier and identity provider
var nameIdentifierClaim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase));
var identityProviderClaim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(CustomClaimTypes.IdentityProviderClaimType, StringComparison.OrdinalIgnoreCase));
if (nameIdentifierClaim == null || identityProviderClaim == null)
{
throw new AuthenticationErrorException("Invalid claims", "The claims provided by your Identity Provider are invalid. Please contact your administrator.");
}
try
{
//checking the database here...
using (var context = new CloudContext())
{
user = (from u in context.Users
where u.IdentityProvider == identityProviderClaim.Value &&
u.NameIdentifier == nameIdentifierClaim.Value &&
!u.Account.PendingDelete
select u).FirstOrDefault();
}
}
catch (System.Data.DataException ex)
{
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
Console.WriteLine(ex.InnerException);
throw;
}
}
return incomingPrincipal;
}
Then, in your web.config, you add a section to the <microsoft.identitymodel> area, as so:
<claimsAuthenticationManager type="CloudAnalyzer.UI.Security.CloudAnalyzerClaimsAuthenticationManager" />
I learned this trick from the sample app located here: Windows Azure Marketplace. Even if you're not going to publish in the Window Azure Marketplace it's a good sample with some helpful code snippets you can use for ACS integration.

How to make my Boot.java class as main always on top where i have other processes causing troubles in Java?

I have this main.Boot which is actually a splash screen requires to be always on top of everything. But in my case what happening is it gets lost and main.main gets the first position which even do not have any setAlwaysOnTop(true);
How can i set main.Boot always on top?
Boot.java:
package main;
public class Boot
{
public static void main(String[] args)
{
try {
String myCmd;
// Layer 2 : it can be any other third party Java applications getting launched
// here its just one example used simple another JWindow...
myCmd = "java -cp /tmp/dist/AnotherProcess.jar main.main";
Runtime.getRuntime().exec(myCmd);
System.out.println("Running: " + myCmd);
} catch(Exception e) {
System.out.println(e);
}
myTimer(); // just a timer counting 40 seconds doing nothing else
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
window = new JWindow();
....
//setFocusable(true);
window.pack();
window.setLayout(new BorderLayout());
window.setSize(screen.width, screen.height+1);
window.setLocationRelativeTo(null);
window.setAlwaysOnTop(true); // Layer 1
// (always on top) > but it gets behind
// what ever was launched using .exec(..)
window.setVisible(true);
}
}
JFrame/JWindow doesn's support Modality correctly back to the Native OS this is job for un_decorated JDialog with following two methods
setAlwaysOnTop
setModal(true)
Notice not possible (Windows OS) to block keys Atl + F4 or Ctlr + Alt + F4
It may not be supported on your platform.
From the docs:
Note: some platforms might not support always-on-top windows. To
detect if always-on-top windows are supported by the current platform,
use Toolkit.isAlwaysOnTopSupported() and isAlwaysOnTopSupported(). If
always-on-top mode isn't supported by the toolkit or for this window,
calling this method has no effect.

Resources