Phone dialer issues in xamarin.plugins.messaging - visual-studio

I am new for Xamarin and I just wanted to directly make a phone call from my Xamarin app.
I just wanted to include the hashtag(#) symbol in the phone number as a string, but it doesn't include the symbol when the program is executed.
Here is the code,
private void Button_Clicked(object sender, EventArgs e)
{
var phoneDialer = CrossMessaging.Current.PhoneDialer;
if (phoneDialer.CanMakePhoneCall)
phoneDialer.MakePhoneCall("*999#");
}
Any help would be appreciated!

Have a look at this thread:
Specifically, if a URL contains the * or # characters, the Phone
application does not attempt to dial the corresponding phone number.
There is also an answer in Swift which says iOS11 now allows us to call number with * or # , I translate it to C# and you can have a try with dependency service:
In shared Project:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
DependencyService.Get<IPhoneCallTask>().DoPhoneCall();
}
}
public interface IPhoneCallTask
{
void DoPhoneCall();
}
In iOS Project:
[assembly: Dependency(typeof(phoneCall))]
namespace App591.iOS
{
class phoneCall : IPhoneCallTask
{
public void DoPhoneCall()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
NSString number = new NSString("*111*12345#");
NSString encode = number.CreateStringByAddingPercentEncoding(NSUrlUtilities_NSCharacterSet.UrlHostAllowedCharacterSet);
NSString header = new NSString("tel://");
string tmp = string.Format("{0}{1}", encode, header);
NSString urlTemp = new NSString(tmp);
if (UIApplication.SharedApplication.CanOpenUrl(new Uri(urlTemp)))
{
UIApplication.SharedApplication.OpenUrl(new Uri(urlTemp));
}
}
}
}
}

Related

How to upper case entry and picker in xamarin forms?

Is there a way to force entry to uppercase and How can I uppercase the items inside the picker? If possible without using plugins
For the Entry, you can change the text to uppercase in TextChanged event.
For the Picker, you usually control the ItemsSource, you just need to uppercase every string in the ItemsSource.
public MainPage()
{
InitializeComponent();
IList<Item> dummyData= new List<Item>
{
new Item { Id = 0, Name = "Item 0" },
new Item { Id = 1, Name = "Item 1" },
new Item { Id = 2, Name = "Item 2" },
};
picker.ItemsSource = dummyData
.Select(i => i.Name.ToUpperInvariant())
.ToList();
entry.TextChanged += OnTextChanged;
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
(sender as Entry).Text = e.NewTextValue.ToUpperInvariant();
}
If you're using MVVM, you can use a custom converter for Entry.Text and Picker.ItemsSource binding to change the value to uppercase.
If you want to force UpperCase in the Entry there are a few ways to do this but let's use Effects this time.
If you haven't heard about Effects you can quickly read what are they for here
First you will need to create the effect in the Xamarin.Forms Project.
For simplicity I will call it EntryAllCapitalEffect and the code looks like this:
namespace YourAwesomeNamespace
{
public class EntryAllCapitalEffect : RoutingEffect
{
public EntryAllCapitalEffect() : base("StackOverflow.EntryAllCapitalEffect")
{
}
}
}
Where StackOverflow is your company name and EntryAllCapitalEffect is the effect name.
Now we need to implement the effect in each one of the Platform Projects.
Let's start with Android:
Let's create a file into the Android Project with the name EntryAllCapitalEffect and add the code below as part of the implementation.
[assembly: ResolutionGroupName("StackOverflow")] //Remember your companyName ?
[assembly: ExportEffect(typeof(YourAwesomeNamespace.Droid.EntryAllCapitalEffect), "EntryAllCapitalEffect")]
namespace YourAwesomeNamespace.Droid
{
public class EntryAllCapitalEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
//Let's don't do anything if the control is not a EditText
if (!(Control is EditText editText))
{
return;
}
//Force the keyboard setup all Caps letters
// But the user can still change the Caps taping on Shift
editText.InputType = InputTypes.TextFlagCapCharacters;
// Update any lowercase into Uppercase
var filters = new List<IInputFilter>(editText.GetFilters());
filters.Add(new InputFilterAllCaps());
editText.SetFilters(filters.ToArray());
}
catch (Exception) { }
}
protected override void OnDetached()
{
}
}
}
Now let's continue with iOS
Same as of Android, let's create a file into the iOS Project with the name EntryAllCapitalEffect. Add the code below into the class.
[assembly: ResolutionGroupName("StackOverflow")] // Again your CompanyName
[assembly: ExportEffect(typeof(YourAwesomeNamespace.iOS.EntryAllCapitalEffect), "EntryAllCapitalEffect")]
namespace YourAwesomeNamespace.iOS
{
public class EntryAllCapitalEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
if (!(Control is UITextField uiTextField))
{
return;
}
//Force the keyboard setup all Caps letters
// But the user can still change the Caps taping on Shift
uiTextField.AutocapitalizationType = UITextAutocapitalizationType.AllCharacters;
//Delegate to replace any Lowercase entry into UpperCase
uiTextField.ShouldChangeCharacters = OnShouldChangeCharacters;
}
catch (Exception) { }
}
protected override void OnDetached()
{
}
private bool OnShouldChangeCharacters(UITextField textfield, NSRange range, string replacementString)
{
using (NSString original = new NSString(textfield.Text), newString = new NSString(replacementString.ToUpper()))
{
textfield.Text = original.Replace(range, newString);
}
return false;
}
}
}
Ok so now to use it just assign it to any Entry in the XAML like this:
<Entry HorizontalOptions="FillAndExpand" Placeholder="Enter Text here" >
<Entry.Effects>
<local:EntryAllCapitalEffect />
</Entry.Effects>
</Entry>
Remember to add the local alias in the XAML
xmlns:local="clr-namespace:YourAwesomeNamespace"
This will be the namespace where your Effect is found.
Note: Your CompanyName can be anything but it must match is all placed this is used.
Note 2: If you have other Effects you don't need to repeat the CompanyName Registration. This is done only once by platform.
Hope this helps.-
Here is on more solution based on #Roger Leblanc's answer
Create a behavior:
public class AllCapsBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
private static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
((Entry)sender).Text = args.NewTextValue.ToUpperInvariant();
}
}
Add namespace reference to view:
xmlns:behav="clr-namespace:yourproject.Resources.Behaviors"
Add behavior to Entry:
<Entry>
<Entry.Behaviors>
<behav:AllCapsBehavior/>
</Entry.Behaviors>
</Entry>

How do I enable WebGL in Xamarin.Forms WebView on UWP?

I’m new to Xamarin.Forms and tried using WebView on my Windows 10 x64 v1803 machine with UWP but I can’t see how to get it to work with WebGL.
Sites which use WebGL either display a message that “Your video card does not support WebGL or just don’t display and graphical content at all.
Is this a limitation of UWP or WebView itself?
Is it a WebView configuration issue?
WebGL works in all other browsers on this machine.
UWP WebView control is support WebGL. There is similar issue case in msdn you could refer. Please try to use SeparateProcess mode WebView to replace the default one.
public MainPage()
{
this.InitializeComponent();
var MyWebView = new WebView(WebViewExecutionMode.SeparateProcess);
MyWebView.Source = new Uri("http://cycleblob.com/");
this.RootGrid.Children.Add(MyWebView);
}
I had the same problem, but with the newer Xamarin Forms it took a little more poking around to get this took work right. However, I do like that they moved the native WebView resolver back to the responsibility of the UWP/iOS/Android project (as a native XAML object) instead of using code branching with compiler directives in the Shared project.
Start by creating a HybridWebView class in the shared project to use as your WebForm view object:
public class HybridWebView : Xamarin.Forms.WebView
{
Action<string> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void Cleanup()
{
action = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
}
Then in the UWP project, create a custom renderer, which will construct the native WebView and relay the events back to the WebForms object in the Shared project:
Put this at the top of the namespace, to link the HybridWebView with the Custom Renderer:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(WebViewRenderer2))]
Then create the renderer class (for the IOS and android projects, if you leave this class out, it defaults to the standard native controls which seem to work fine for me):
public class WebViewRenderer2 : ViewRenderer<Xamarin.Forms.WebView, Windows.UI.Xaml.Controls.WebView>, IWebViewDelegate
{
Windows.UI.Xaml.Controls.WebView _control;
public void LoadHtml(string html, string baseUrl)
{
}
public void LoadUrl(string url)
{
}
protected override void Dispose(bool disposing)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
if (_control == null) {
_control = new Windows.UI.Xaml.Controls.WebView(WebViewExecutionMode.SeparateProcess);
SetNativeControl(_control);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var xamWebView = sender as HybridWebView;
switch(e.PropertyName.ToLower())
{
case "source":
var urlSource = xamWebView.Source as Xamarin.Forms.UrlWebViewSource;
_control.Source = new Uri(urlSource.Url);
break;
case "width":
_control.Width = xamWebView.Width;
break;
case "height":
_control.Height = xamWebView.Height;
break;
case "isfocused":
var focused = xamWebView.IsFocused;
if (focused)
_control.Focus(FocusState.Programmatic);
else
_control.Focus(FocusState.Unfocused);
break;
}
}
}
You can also use the Custom Renderer to inject scripts, and you can use it to communicate from the native webview back to the Xamarin App, as seen here: HybridWebView Communication

How to open file .doc use "Word" app on Xamarin Forms?

Use Xamarin Forms and on iOS, how to check and open Word app when Open file by UrL?
Reference: https://learn.microsoft.com/en-us/office/client-developer/integration/integrate-with-office-from-ios-applications
This is my code, it isn't work:
Device.OpenUri(new Uri("ms-word:ofe|u|https://calibre-ebook.com/downloads/demos/demo.docx"));
Please help me!
Thanks!
What you are asking here can be done using a simple WebView in iOS:
First, create a custom WebView class that allows you to pick file uri:
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(CustomWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
Then in ios make a renderer for the same and do something like this:
[assembly: ExportRenderer (typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DisplayPDF.iOS
{
public class CustomWebViewRenderer : ViewRenderer<CustomWebView, UIWebView>
{
protected override void OnElementChanged (ElementChangedEventArgs<CustomWebView> e)
{
base.OnElementChanged (e);
if (Control == null) {
SetNativeControl (new UIWebView ());
}
if (e.OldElement != null) {
// Cleanup
}
if (e.NewElement != null) {
var customWebView = Element as CustomWebView;
string fileName = Path.Combine (NSBundle.MainBundle.BundlePath, string.Format ("Content/{0}", WebUtility.UrlEncode (customWebView.Uri)));
Control.LoadRequest (new NSUrlRequest (new NSUrl (fileName, false)));
Control.ScalesPageToFit = true;
}
}
}
}
Then use the custom control like this:
<local:CustomWebView Uri="FooPath" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
Where FooPath is the path for the doc file.
I have solution for my project, I try it:
If you only open file .docx on iOS, you could write code at Share Code of iOS:
Check device of user has setup app (Word, Excel, PP, etc...)
public static bool HasSetupAppDocument(string extension)
{
if (string.IsNullOrEmpty(extension))
return false;
// Device has setup app?
var result = UIApplication.SharedApplication.CanOpenUrl(NSUrl.FromString($"{extension}"));
return result;
}
(Ex: extension is ms-word: or ms-excel: or ms-excel:
Reference: https://learn.microsoft.com/en-us/office/client-developer/integration/integrate-with-office-from-ios-applications#office-protocols)
Notes: Add source to Info.plist:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>ms-word</string>
<string>ms-excel</string>
<string>ms-powerpoint</string>
</array>
At Class Dependencies, open file with URL:
Device.OpenUri(new Uri($"{convertExtension}{url}"));
Note: url is link file share on Onedrive and Be sure that account Onedrive as same as account login Word app (if you had set security).
If file has mode Read-only, app Word will open file with mode Read-only.

How to create a code-only webview with Xamarin.Forms

I'm trying to use a library that doesn't has a .Net SDK, but as I want to use it only to return a string, I thought I could use it's JS SDK by creating a custom WebView that returns strings (https://xamarinhelp.com/xamarin-forms-webview-executing-javascript/).
The first problem that I faced was that a CustomRenderer is not called in Xamarin.Forms until the View is added to a Page (or at least I couldn't make it be called). To fix this I added a call to Platform.CreateRenderer in each platform.
It did the trick and the CustomRenderer executed. But when I tried to call a JS function to retrieve a string, the app just hung and stayed that way.
I didn't try to insert the WebView in a Page because I want it to be independent of the page that the app is current on, and as I want a "code-only" html, I don't see the point of adding it somewhere.
My classes:
JSEvaluator
namespace MyNamespace.Views
{
public class JSEvaluator : WebView
{
public static BindableProperty EvaluateJavascriptProperty = BindableProperty.Create(nameof(EvaluateJavascript), typeof(Func<string, Task<string>>), typeof(JSEvaluator), null, BindingMode.OneWayToSource);
public Func<string, Task<string>> EvaluateJavascript
{
get { return (Func<string, Task<string>>)GetValue(EvaluateJavascriptProperty); }
set { SetValue(EvaluateJavascriptProperty, value); }
}
public JSEvaluator()
{
}
}
}
UWP Renderer
[assembly: ExportRenderer(typeof(JSEvaluator), typeof(JSEvaluatorRenderer))]
namespace MyNamespace.UWP.Renderers
{
public class JSEvaluatorRenderer : WebViewRenderer
{
public JSEvaluatorRenderer() { }
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
var webView = e.NewElement as JSEvaluator;
if (webView != null)
webView.EvaluateJavascript = async (js) =>
{
return await Control.InvokeScriptAsync("eval", new[] { js });
};
}
}
}
Creation and use
if (jsEvaluator == null)
{
jsEvaluator = new JSEvaluator { Source = new HtmlWebViewSource { Html = HTML.html } };
#if __ANDROID__
Xamarin.Forms.Platform.Android.Platform.CreateRenderer(jsEvaluator);
#elif __IOS__
Xamarin.Forms.Platform.iOS.Platform.CreateRenderer(jsEvaluator);
#elif WINDOWS_UWP
Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(jsEvaluator);
#endif
}
Thanks for the help :)
I had to add the WebView to a page, as #SushiHangover said in the comment. With this done, it worked as expected.

Simple navigation in Windows 8 web view

I'm working on porting a Windows Phone 8 application to tablet, and I've bumped into a problem with the WebView API. In Windows Phone 8 and Windows 8.1, the WebBrowser and WebView controls both have a GoBack() method. However, I need my application to be compatible for Windows 8, whose WebView API does not have such a method. Are there any alternatives/workarounds that anyone's used for Windows 8 apps?
In the end I just ended up writing a wrapper for the WebView to manage the navigation stack. Here's the relevant code, for anyone who's interested. Note that I only needed to handle backwards navigation, so I used a Stack. If forwards navigation is also required, it'd probably make sense to replace the Stack with a List and store the index of the current page instead.
public class WebViewWrapper
{
private Stack<Uri> _navigationStack;
private Uri _currentUri;
public WebView WebView { get; private set; }
public bool CanGoBack
{
get { return _navigationStack.Count > 0; }
}
public WebViewWrapper(WebView _webView)
{
_navigationStack = new Stack<Uri>();
WebView = _webView;
WebView.LoadCompleted += (object s, NavigationEventArgs e) => {
if (_currentUri != null)
{
_navigationStack.Push(_currentUri);
}
_currentUri = e.Uri;
};
}
public void GoBack()
{
if (CanGoBack)
{
_currentUri = null;
WebView.Navigate(_navigationStack.Pop());
}
}
}
An example of usage would be as follows:
// Code behind for a view called WebBrowserPage
public sealed partial class WebBrowserPage : Page
{
private WebViewWrapper _webViewWrapper;
public WebBrowserPage()
{
// webView is a WebView in the xaml with x:Name="webView"
_webViewWrapper = new WebViewWrapper(webView);
}
// Other code for navigating to a Uri specified in a ViewModel.
// Event handler for a back button press
private void BackButton_Click(object sender, RoutedEventArgs e)
{
if (_webViewWrapper.CanGoBack)
{
_webViewWrapper.GoBack();
}
else
{
// Code that executes a command in the ViewModel to leave the WebBrowserPage
}
}
}
WinRT XAML Toolkit has a WebBrowser control that does some of that, but I haven't used it in any app, so I can't vouch for its quality.

Resources