I just migrate my Xamarin iOS app to Xamarin Unified using the Migration Tool.
The code below was working fine and the app didn’t have any error or warning before the migration.
After the migration I got the following errors
Error-1
PresentViewController doesn’t accept the MediaPickerController object as a parameter.
Error-2
mediaPickerController doesn’t have the method DismissViewController
protected void TakePicture()
{
MediaPickerController mediaPickerController = mediaPicker.GetTakePhotoUI(new StoreCameraMediaOptions
{
Name = this.PictureName + ".jpg",
DefaultCamera = CameraDevice.Rear
});
if (!mediaPicker.IsCameraAvailable)
{
ShowUnsupported();
}
//Error-1
PresentViewController(mediaPickerController, true, null);
try
{
mediaPickerController.GetResultAsync().ContinueWith(t =>
{
BTProgressHUD.Show("Processing");
// Dismiss the UI yourself
//Error-2
mediaPickerController.DismissViewController(true, () =>
{
if (t.IsCanceled || t.IsFaulted)
{
BTProgressHUD.Dismiss();
return;
}
MediaFile file = t.Result;
FinishedPickingMedia(file);
BTProgressHUD.Dismiss();
});
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
Insights.Report(ex, ReportSeverity.Error);
}
}
Download the latest Xamarin.Mobile dll from here https://components.xamarin.com/view/xamarin.mobile and reference the lib/ios-unified/Xamarin.Mobile.dll instead of the old dll.
This will fix the errors.
Related
I have created an IOS app using React Native. The app consists of a Song Menu screen and a song screen. On the song screen the user is able to press the play button to play the song.
I am currently testing it out using TestFlight. It is working fine on my phone. However, on my friend's phone it keeps crashing. The error is very generic giving RCTFatal as the error.
However, I have narrowed the problem down to code which stops songs from playing when the user navigates away from the Song page.
The relevant code is here:
export default class Song extends Component {
playAudio = (file) => {
var s = new Sound('audio/' + file, Sound.MAIN_BUNDLE, (error) => {
if (error){
console.log('error', error)
} else {
s.play(() => {
s.release()
})
}
})
/* Problem LINE #1 */
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
() => s.release()
)
}
/* Problem LINE #2 */
componentWillUnmount(){
this.willBlurSubsciption.remove()
}
/* Other code here for displaying UI and the clickable audio button which loads the playAudio function. */
...
}
When I remove the subscription code above (shown on two lines) then there is no crash. However, the song will not stop playing after the user goes back to the main menu. When I put the lines back in there it crashes for my tester with the RCTFatal error.
Note: The app crashes whether my tester plays the audio file or not, but always when he navigates back to the Song Menu.
What is the problem with my code? Why is it generating such a cryptic error? And why does my IOS device not crash but his does?
I guess, from the react-navigation event you're using (willBlur), the version of react-navigation is <=4.x, so the event subscription methods looks correct. If you're using react-navigation version 5 then these events have totally changed.
You should be very careful using these event subscriptions when disposing native modules.
You should try to be safe by checking if each function/method exists before calling it and of course wrap every function call to a try..catch error handler:
playAudio = (file) => {
// If audio playback is triggered by user,
// then you should always check if there is already an object
// and if there is, either exit the function or stop/dispose current sound and start a new one
if (this.sound) {
// either return and let the current sound play
// return;
// or stop and release the sound if you have play/stop/pause sound controls
try {
this.sound.release()
} catch(error) {}
finally {
this.sound = null
}
}
this.sound = new Sound(`audio/${file}`, Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log('error', error)
this.sound = null;
} else {
this.sound.play(() => {
try {
if (this.sound) {
this.sound.release()
}
} catch(error) {}
finally {
this.sound = null
}
})
}
})
/* Problem LINE #1 */
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
() => {
try {
if (this.sound) {
this.sound.release()
}
} catch(error) {}
finally {
this.sound = null
}
}
)
}
/* Problem LINE #2 */
componentWillUnmount() {
try {
this.willBlurSubsciption &&
this.willBlurSubsciption.remove &&
this.willBlurSubsciption.remove()
} catch(error) {}
finally {
this.willBlurSubsciption = null
}
}
I guest this.willBlurSubscription = this.props.navigation.addListener will create one listener every playAudio invoked. So from the second time, the s will be released 2 times -> cause the cash.
Try to push the listener in componentDidMount or check the listener before add it, like:
/* Problem LINE #1 */
if (this.willBlurSubscription) {
this.willBlurSubsciption.remove();
this.willBlurSubsciption = null;
}
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
() => s.release()
)
I am working on Xamarin.Forms app and it's working perfectly fine on Android device. Anyway, when I am trying to run it on iPhone simulator it's just showing the main screen of the app, but none of the features are working.
The main screen consists of two parts of which one is to browse and open files and the other is to open a menu. The layout consists of Browse, process and exit buttons and when I click on the browse button to open file explorer an alert is displayed, that something went wrong.
I enabled breakpoints and tried debugging it, but the control is going to catch exception part directly.
Here is the code for it can anyone please help me with this part? I am using Xamarin.Plugin.Filepicker NuGet package. When I place the cursor on the Exception I can see that
System.NotImplemented Exception:This functionality is not implemented in the portable version of this assembly,you should reference the NuGet Package from your main application project in order to reference the platform specific
and the code is
private Plugin.FilePicker.Abstractions.FileData file =
default(Plugin.FilePicker.Abstractions.FileData);
public async void OnBrowse(object o, EventArgs args)
{
try
{
// var file_path =
this.file = await CrossFilePicker.Current.PickFile();
if (this.file == null)
{
return;
}
string extensionType = this.file.FileName.Substring(
this.file.FileName.LastIndexOf(".",
StringComparison.Ordinal) + 1,
this.file.FileName.Length -
this.file.FileName.LastIndexOf(".", StringComparison.Ordinal) -
1).ToLower();
fileName = this.file.FileName;
if (extensionType.Equals("csv"))
{
csv_file.Text = (fileName);
}
else
{
await this.DisplayAlert("Name of the file:" + file.FileName, "File info", "OK");
}
if (SettingsPage.loggingEnabled)
{
LogUtilPage.Initialize("/storage/emulated/0");
}
}
catch (Exception e)
{
await DisplayAlert("Alert", "Something went wrong", "OK");
if (SettingsPage.loggingEnabled)
{
LogUtilPage.Log(e.Message);
}
}
}
Im doing a POC of implementing the NFCTagReader into a xamarin.ios app.
https://developer.xamarin.com/samples/monotouch/ios11/NFCTagReader/
I've taken the NFCTagReader from the xamarin site and set all the appropriate provision settings to get access to the tag reader. The problem is that when i click scan the "Ready to Scan" window pops up as expected then i scan a tag and it shows the little tick on the screen to show that it found but it never breaks into the DidDetect method of my code in the delegate. It will hit the DidInvalidate method and give the code for ReaderSessionInvalidationErrorUserCanceled.
Any ideas what i'm missing. Following is my code snippet:
partial void Scan(UIBarButtonItem sender)
{
InvokeOnMainThread(() =>
{
Session = new NFCNdefReaderSession(this, null, true);
if (Session != null)
{
Session.BeginSession();
}
});
}
#endregion
#region NFCNDEFReaderSessionDelegate
public void DidDetect(NFCNdefReaderSession session, NFCNdefMessage[] messages)
{
foreach (NFCNdefMessage msg in messages)
{
DetectedMessages.Add(msg);
}
DispatchQueue.MainQueue.DispatchAsync(() =>
{
this.TableView.ReloadData();
});
}
public void DidInvalidate(NFCNdefReaderSession session, NSError error)
{
var readerError = (NFCReaderError)(long)error.Code;
if (readerError != NFCReaderError.ReaderSessionInvalidationErrorFirstNDEFTagRead &&
readerError != NFCReaderError.ReaderSessionInvalidationErrorUserCanceled)
{
InvokeOnMainThread(() =>
{
var alertController = UIAlertController.Create("Session Invalidated", error.LocalizedDescription, UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create("Ok", UIAlertActionStyle.Default, null));
DispatchQueue.MainQueue.DispatchAsync(() =>
{
this.PresentViewController(alertController, true, null);
});
});
}
}
Little bit of a blonde moment and was just going to close this question but thought would answer this just in case someone else comes across the same problem as I did.
The problem ended up being caused by the fact that the tags that I was given were blank. Therefore the phone would click when it detected the tag but would never hit the didDetect method. As soon as I wrote something to the NFC tag with an Android tag writer app then DidDetect fired as expected.
I just migrate my Xamarin iOS app to Xamarin Unified using the Migration Tool. The code below was working fine and the app didn’t have any error or warning before the migration. After the migration I got the following errors Error-1 PresentViewController doesn’t accept the MediaPickerController object as a parameter. Error-2 mediaPickerController doesn’t have the method DismissViewController
protected void TakePicture()
{
MediaPickerController mediaPickerController = mediaPicker.GetTakePhotoUI(new StoreCameraMediaOptions
{
Name = this.PictureName + ".jpg",
DefaultCamera = CameraDevice.Rear
});
if (!mediaPicker.IsCameraAvailable)
{
ShowUnsupported();
}
//Error-1
PresentViewController(mediaPickerController, true, null);
try
{
mediaPickerController.GetResultAsync().ContinueWith(t =>
{
BTProgressHUD.Show("Processing");
// Dismiss the UI yourself
//Error-2
mediaPickerController.DismissViewController(true, () =>
{
if (t.IsCanceled || t.IsFaulted)
{
BTProgressHUD.Dismiss();
return;
}
MediaFile file = t.Result;
FinishedPickingMedia(file);
BTProgressHUD.Dismiss();
});
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
Insights.Report(ex, ReportSeverity.Error);
}
}
You need to update your Xamarin component that contains MediaPickerController to the latest version compatible with Xamarin.iOS unified code!
The latest version of Xamarin.Mobile is 0.7.6. Double check with your project if your are using an older one.
I get an exception when i try to upgrade my indexedDB database with a higher version then the browser currently has,
but the funny part abort is that, it gets upgraded. Is this by design or have i done something wrong.
I got very inspired from the dart sample Todo, so my code ended up looking like this.
void open_db(String DB_name, int Version, String Store_Name){
var request = window.indexedDB.open(DB_name, Version);
request.on.success.add((e) => _onDbOpened(request.result));
request.on.error.add((e) => print("Error opening db"));
request.on.upgradeNeeded.add((e) => _onUpgradeNeeded(request.transaction, Store_Name));
}
void _onDbOpened(IDBDatabase db){
_db = db;
print("DB opened");
}
void _onUpgradeNeeded(IDBTransaction changeVersionTransaction, String Store_Name){
changeVersionTransaction.on.error.add((e) => print("Error upgrading db"));
changeVersionTransaction.on.complete.add((e) => print("Success upgrading db"));
changeVersionTransaction.db.createObjectStore(Store_Name);
}
When I run this with version=4 and the browser only have version=3, then it jumps to _onUpgradeNeeded as expected, but I get an IDBDatabaseException with message: "ConstraintError: DOM IDBDatabase Exception 4".
So where is it I go wrong?
Thanks for your question!
You may need to check if the store exists first.
if (db.objectStoreNames.indexOf(storeName) == -1) {
db.createObjectStore(storeName);
}
Here is some code to update your IndexedDB database, using Dart. Note, this compensates for the two ways to upgrade (an old way that Chrome used, and the new way that Firefox and newer versions of Chrome use)
_openDb(afterOpen()) {
var request = window.indexedDB.open(DB_NAME, VERSION);
if (request is IDBOpenDBRequest) {
// New upgrade protocol. FireFox 15, Chrome 24, hopefully IE10.
request.on.success.add(expectAsync1((e) {
db = e.target.result;
afterOpen();
}));
request.on.upgradeNeeded.add((e) {
guardAsync(() {
_createObjectStore(e.target.result);
});
});
request.on.error.add(fail('open'));
} else {
// Legacy setVersion upgrade protocol. Chrome < 23.
request.on.success.add(expectAsync1((e) {
db = e.target.result;
if (db.version != '$VERSION') {
var setRequest = db.setVersion('$VERSION');
setRequest.on.success.add(
expectAsync1((e) {
_createObjectStore(db);
var transaction = e.target.result;
transaction.on.complete.add(
expectAsync1((e) => afterOpen()));
transaction.on.error.add(fail('Upgrade'));
}));
setRequest.on.error.add(fail('setVersion error'));
} else {
afterOpen();
}
}));
request.on.error.add(fail('open'));
}
}
_createObjectStore(db) {
try {
// Nuke object store if it already exists.
db.deleteObjectStore(STORE_NAME);
}
on IDBDatabaseException catch(e) { } // Chrome
on DOMException catch(e) { } // Firefox
db.createObjectStore(STORE_NAME);
}
Note, this code is from this test: http://code.google.com/p/dart/source/browse/trunk/dart/tests/html/indexeddb_3_test.dart