I implemented App Center push notifications in my MonoGame Android project and everything seems to work, because I receive the notifications on my Android device that I have sent from my App Center account. But in this tutorial, they mention that you should add this code to your Acitivity class if your LaunchMode is SingleInstance, but the code isn't working. I get two error messages.
Tutorial: see Intercept push notifications, Additional setup
Is this code really necessary when you have an Android project without a splashscreen? Would it make a difference if I add a splashscreen to my project?
What is this code doing and how could I use it in a MonoGame Android project if it would be necessary?
protected override void OnNewIntent(Android.Content.Intent intent)
{
base.OnNewIntent(intent);
Push.CheckLaunchedFromNotification(this, intent);
}
The type or namespace name 'Content' does not exist in the namespace
(are you missing an assembly reference?)
'Activity1.OnNewIntent(Content.Intent)': no suitable method found to
override (CS0115)
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Views;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Microsoft.AppCenter.Push;
namespace Newapp.Android
{
[Activity(Label = "Newapp.Android"
, MainLauncher = true
, Icon = "#drawable/icon"
, Theme = "#style/Theme.Splash"
, AlwaysRetainTaskState = true
, LaunchMode = LaunchMode.SingleInstance
, ScreenOrientation = ScreenOrientation.FullUser
, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize)]
public class Activity1 : Microsoft.Xna.Framework.AndroidGameActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
if (!AppCenter.Configured)
{
Push.PushNotificationReceived += (sender, e) =>
{
// Add the notification message and title to the message
var summary = $"Push notification received:" +
$"\n\tNotification title: {e.Title}" +
$"\n\tMessage: {e.Message}";
// If there is custom data associated with the notification,
// print the entries
if (e.CustomData != null)
{
summary += "\n\tCustom data:\n";
foreach (var key in e.CustomData.Keys)
{
summary += $"\t\t{key} : {e.CustomData[key]}\n";
}
}
// Send the notification summary to debug output
System.Diagnostics.Debug.WriteLine(summary);
};
}
AppCenter.Start("{Your App Secret}", typeof(Analytics), typeof(Crashes), typeof(Push));
var g = new Game1();
SetContentView((View)g.Services.GetService(typeof(View)));
g.Run();
}
protected override void OnNewIntent(Android.Content.Intent intent)
{
base.OnNewIntent(intent);
Push.CheckLaunchedFromNotification(this, intent);
}
}
}
You're seeing the compiler error because the namespace in your project ends with Android so it's trying to find NewApp.Android.Content.Intent not Android.Content.Intent. You can fix the error by changing your namespace to not end with Android, or you can use global:: when referencing the global Android namespace:
protected override void OnNewIntent(global::Android.Content.Intent intent)
{
base.OnNewIntent(intent);
Push.CheckLaunchedFromNotification(this, intent);
}
Related
Im currently having an issue loading a local pdf into a webview. I have the code which works without any errors and when I run it on the iPad simulator, it works absolutely perfect. However, the issue comes when I try to run it on a physical iPad device. When I run it and it gets to the point where it needs to show the PDF, the webview loads but there is no PDF shown in the webview.
The PDF is actually generated by the app and I store it inside a directory inside the library folder.
Code to show the PDF in the WebView:
public void LoadPdfToWebView(string pdfPath)
{
//Console.WriteLine("Load request started");
WebView.LoadRequest(new NSUrlRequest(new NSUrl(pdfPath, false)));
View.AddSubview(WebView);
//Console.WriteLine("Load request Finished");
}
Not really sure why this would be the case and hopefully somebody can help.
I've just had to fix this for an app and thought I'd post the solution
This is for WKWebView which is a requirement from Apple as of Dec 2020 though the deadline has been temporarily extended
Xaml PdfWebView ContentPage
<controls:PdfWebView
Source="{Binding PDFSource}"
HeightRequest="1000"
WidthRequest="1000"/>
control
namespace XForms.Controls
{
public class PdfWebView : WebView { }
}
VM, only the relevant part
private string _pdfSource;
public string PDFSource
{
get => _pdfSource;
set
{
if (Device.RuntimePlatform == Device.Android && value.StartsWith("file:") == false)
{
value = $"file:///android_asset/pdfjs/web/viewer.html?file=file:///{WebUtility.UrlEncode(value)}";
}
SetProperty(ref _pdfSource, value);
}
}
iOS renderer for PdfWebView
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XForms.Controls;
using WebKit;
using Foundation;
[assembly: ExportRenderer(typeof(PdfWebView), typeof(iOSUI.Renderers.PdfWebViewRenderer))]
namespace iOSUI.Renderers
{
public class PdfWebViewRenderer : ViewRenderer<WebView, WKWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var wkWebViewConfiguration = new WKWebViewConfiguration();
var wkWebView = new WKWebView(Frame, wkWebViewConfiguration)
{
AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
};
SetNativeControl(wkWebView);
}
if (e.NewElement != null)
{
if (string.IsNullOrEmpty(((UrlWebViewSource)e.NewElement.Source)?.Url) == false)
{
var url = ((UrlWebViewSource)e.NewElement.Source).Url;
if(url.StartsWith("http"))
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(url)));
}
else
{
Control.LoadFileUrl(new NSUrl($"file://{url}"), new NSUrl($"file://{url}"));
}
}
}
}
}
}
Android Renderer
using System.Net;
using Android.Content;
using Android.Views;
using Android.Webkit;
using XForms.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(PdfWebView), typeof(AndroidUI.Renderers.PDFViewRenderer))]
namespace AndroidUI.Renderers
{
public class PDFViewRenderer : WebViewRenderer
{
public PDFViewRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Settings.JavaScriptEnabled = true;
Control.Settings.DomStorageEnabled = true;
Control.Settings.AllowFileAccess = true;
Control.Settings.AllowFileAccessFromFileURLs = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.SetWebChromeClient(new WebChromeClient());
}
}
// If you want to enable scrolling in WebView uncomment the following lines.
public override bool DispatchTouchEvent(MotionEvent e)
{
Parent.RequestDisallowInterceptTouchEvent(true);
return base.DispatchTouchEvent(e);
}
}
}
This solution uses pdfjs in Android and WKWebview in iOS to render the PDF
The PDFSource is the full path to the file, I use System.IO .net standard calls to handle this in a cross platform way
All the files are stored in (I have a method called GetFullPath to return the cross platform common path)
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Combined with a filename with Path.Combine
Path.Combine(GetFullPath(), fileName);
That is the PDFSource that gets set in the VM
The Pdfjs library files are just copied into Assets/pdfjs for Android
The magic for iOS is just calling LoadFileUrl instead of LoadRequest and prepending "file://"
I've slightly sanitised our namespaces so some of them wont resolve like XForms.Controls and so on that refer to our internal code
In Xamarin.IOS to show a document type other than HTML in a UIWebView:
Add the document (for example, a PDF) to your Xamarin.iOS project. Set the Build Action to BundleResource. You can set the build action for a file by right-clicking on that file and and choosing Build Action in the menu that opens.
Create a UIWebView and add it to a view:
webView = new UIWebView (View.Bounds);
View.AddSubview(webView);
Load the file using NSUrl and NSUrlRequest classes:
string fileName = "Loading a Web Page.pdf"; // remember case-sensitive
string localDocUrl = Path.Combine (NSBundle.MainBundle.BundlePath, fileName);
webView.LoadRequest(new NSUrlRequest(new NSUrl(localDocUrl, false)));
webView.ScalesPageToFit = true;
You can refer to this officical steps.If have problems or other needs, you can refer to this link
If you can't read the resources in the bundle, you can put the resource cache in the temp directory of the sandbox and try to read it using LoadRequest.
recently i tried to learn android programming with Xamarin in Visual studio 2017
i wrote a simple app that makes call but when i tap Call Button its give this execption error a couple of days ago its worked fine but now i got this error
i did make permission for CALL_PHONE in manifest file
forgive me for my bad english
if anyone knows how to fix this issue let me know ill be greatfull
here is my Code .cs
using Android.App;
using Android.Widget;
using Android.OS;
using Android.Content;
namespace Dialer.app
{
[Activity(Label = "Dialer.app", MainLauncher = true)]
public class MainActivity : Activity
{
Button btnCall;
ListView txtViewNumbers;
EditText txtUnumber;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
btnCall = FindViewById<Button>(Resource.Id.button1);
txtViewNumbers = FindViewById<ListView>(Resource.Id.listView1);
txtUnumber = FindViewById<EditText>(Resource.Id.editText1);
string phone = txtUnumber.Text;
btnCall.Click += delegate
{
var callDialog = new AlertDialog.Builder(this);
callDialog.SetMessage("Dial This Number? " + phone);
callDialog.SetPositiveButton("ok", delegate
{
var callIntent = new Intent(Intent.ActionCall);
callIntent.SetData(Android.Net.Uri.Parse(phone));
StartActivity(callIntent); //i get error in this line
});
callDialog.SetNeutralButton("Cancel", delegate { });
callDialog.Show();
};
}
}
}
No Activity found to handle Intent { act=android.intent.action.CALL .....
You are missing the tel: prefix on the phone number:
var callIntent = new Intent(Intent.ActionCall);
callIntent.SetData(Android.Net.Uri.Parse("tel:" + phone));
StartActivity(callIntent);
But, in the latest API levela CALL_PHONE is a revoked permission:
Permission Denial: starting Intent { act=android.intent.action.CALL dat=tel:xxx-xxx-xxxx
Instead of being allowed to directly dial a number, you need the user to accept the number via the system dialer, this is done via ACTION_DIAL:
var callIntent = new Intent(Intent.ActionDial);
callIntent.SetData(Android.Net.Uri.Parse("tel:" + "555-555-1212"));
StartActivity(callIntent);
I'm currently working on Xamarin using Visual Studio to try and build and create an app that reads a bar code and saves the integer it gets from it in a .txt file. I have managed to make the code both read the bar code and save it however i was wondering if there is a way i could save it in a more accessible file, as right now its saving in internal storage and the only way i can reach it is through adb console.
Is there a way for me to perhaps save the integers on a .txt file on my laptop? I'm currently testing it on my physical phone and its connected to my laptop via a USB cable.
Here is my code:
using Android.App;
using Android.Widget;
using Android.OS;
using System;
using Android.Content;
using ZXing.Mobile;
using System.IO;
namespace Scanner
{
[Activity(Label = "Scanner", 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);
Button buttonScan = FindViewById<Button>(Resource.Id.buttonScan);
TextView scanText = FindViewById<TextView>(Resource.Id.scanText);
var documents = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var BarcodesFile = Path.Combine(documents, "Barcodes.txt");
buttonScan.Click += async (sender, e) =>
{
MobileBarcodeScanner.Initialize(Application);
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
if (result != null)
File.AppendAllText(BarcodesFile, "Scanned Barcode: " + result.Text);
scanText.Text = File.ReadAllText(BarcodesFile);
};
}
}
}
So if api is an idea. I have not used any api yet for those requirements but when I think about txt I immediately thought about pastebin.
https://pastebin.com/api enter code here
That might be usefull to check out. Goodluck!;)
I'm in the process of learning SQLite and wanted to make my own very simple proof of concept app where I simply store and retrieve a value from a database. I use the NuGet package SQLite-net by Krueger.
My problem is everything seems to work except it doesn't retrieve the value, it crashes at "string a = db.GetAsync(0).Result.storedvalue.ToString();", only saying multiple errors ocurred. Is there something wrong with this line, or perhaps is there something wrong with how I store values in the first place?
Here is the complete C# code for the app:
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using SQLite;
using System.IO;
using System.Reflection;
namespace SimpleDatabaseTest
{
[Activity(Label = "SimpleDatabaseTest", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
SQLiteConnection db;
int i;
int k;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// create database
db = new SQLiteConnection(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal),"test.sqlite"));
db.CreateTable<somevalues>();
// set up enter_value and show_value
EditText enter_value = FindViewById<EditText>(Resource.Id.enter_value);
TextView show_value = FindViewById<TextView>(Resource.Id.show_value);
// store value button
Button store_value = FindViewById<Button>(Resource.Id.store_value);
store_value.Click += delegate
{
somevalues newTable = new somevalues();
i = int.Parse(enter_value.Text);
newTable.storedvalue = i;
k = newTable.id;
db.Insert(newTable);
Toast toast = Toast.MakeText(ApplicationContext, k.ToString(), ToastLength.Long); //enter_value.Text
toast.Show();
};
// retrieve value button
Button retrieve_value = FindViewById<Button>(Resource.Id.retrieve_value);
retrieve_value.Click += delegate
{
somevalues some = db.Get<somevalues>("id");
//string a = some.storedvalue.ToString();
//Toast toast = Toast.MakeText(ApplicationContext, a, ToastLength.Long);
//toast.Show();
//show_value.Text = a;
};
}
}
}
I'm trying to create a simple test app to take photos in Android, using Xamarin. When I get this app working (or so I hope), i'll use the code in a real app that I'm working on. I'm using the following recipe from Xamarin as my basis:
http://docs.xamarin.com/recipes/android/other_ux/camera_intent/take_a_picture_and_save_using_camera_app/
The major difference is that I need to store images locally, and not on the SD card. I'm able to successfully take a picture (with the Android simulator). I can see the file in the file structure using ADB and can successfully copy and open the file on my PC. However, I'm unsuccessfull in accessing the file in the app, probably due to user rights.
Please note that I was successfull in creating my own .txt files, and reading them back using either System.IO and Java.IO.
Please review the following code. My app crashes when using "System.IO.File.ReadAllText" and gives me "Access to the path "/data/data/CameraAppDemo.CameraAppDemo/files/photo.jpg" is denied.". And whatever I try (absolute, relative paths, uri's), objBitmap is always null.
ADB says that "photo.jpg" has -rwxrwx--- rights, and though I'm not entirely sure, I think that should be more than sufficient
On the other hand, maybe the intent still has a lock on "photo.jpg"? Or something else is going on...
And one final note, I'm using System.IO.File.ReadAllText just for testing purposes. I experimented with stream readers as well, but with the same result. Also, though I believe this step is unnecessary, I enabled "WriteExternalStore" in the Manifest
namespace CameraAppDemo
{
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.OS;
using Android.Provider;
using Android.Widget;
using Java.IO;
using Environment = Android.OS.Environment;
using Uri = Android.Net.Uri;
[Activity(Label = "Camera App Demo", MainLauncher = true)]
public class MainActivity : Activity
{
private File _file;
private string _basePath;
private ImageView _imageView;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
var objBitmap = BitmapFactory.DecodeFile(_file.AbsolutePath) ;
Console.WriteLine ("objBitmap = null : " + (objBitmap == null).ToString ());
var strOutput = System.IO.File.ReadAllText (FileManager.BasePath + "/photo.jpg");
Console.WriteLine (strOutput);
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
FileManager.SetupFolderStructure();
if (IsThereAnAppToTakePictures())
{
Button button = FindViewById<Button>(Resource.Id.myButton);
_imageView = FindViewById<ImageView>(Resource.Id.imageView1);
button.Click += TakeAPicture;
}
}
private bool IsThereAnAppToTakePictures()
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
IList<ResolveInfo> availableActivities = PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
return availableActivities != null && availableActivities.Count > 0;
}
private void TakeAPicture(object sender, EventArgs eventArgs)
{
System.IO.Directory.Delete (FileManager.BasePath, true);
_basePath = FileManager.BasePath;
_file = new Java.IO.File (_basePath, "photo.jpg");
Intent intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(_file));
StartActivityForResult(intent, 0);
}
}
}
//Part of the FileManager class:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Android.Graphics;
namespace CameraAppDemo
{
public class FileManager
{
public static string BasePath {
get {
var libraryPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
if (Directory.Exists (libraryPath) == false) {
Directory.CreateDirectory (libraryPath);
}
return libraryPath;
}
}
}
}
==== Edit ====
It seems that I'm simply not able to read the file. As an ex-webdeveloper, I'm fairly new to programming for mobile, let alone the combo of C# and Java and I'm still learning a lot.
Anyway, I added the following lines:
Console.WriteLine("Setting file :" + _file.SetReadable (true));
Console.WriteLine("Can read :" + _file.CanRead());
Both cases return False. I can't read the file, and I am unable to give read access.
So, any ideas? Is this by design? Can I tell the Intent for taking images to give me read access, or is there another workaround?
If everything fails, I'm hoping to workaround the problem by saving to the SD card first and then copying the file to the local filesystem. But that's something I rather would not do; I can't guarantee that the end users have an SD card, and the pictures should not be deleted by accident.