How to play video in iPhone without fullscreen mode using WebView in Xamarin.Forms? - iphone

I am using WebView for playing video in my Xamarin.Forms project. On iPhone the video is playing in fullscreen, but I need to play the video within the WebView without going to fullscreen.
I have this issue only on the iPhone. On Android, Windows, and iPad devices the video is playing without fullscreen.
Case 1: Normal WebView
<WebView
x:Name="web_view"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"/>
web_view.Source = videoUrl;
Case 2: Custom webview
On some part, I am using a custom WebView. In this case the video is also being played in full-screen mode.
public class MyWebView : WebView
{
public static readonly BindableProperty UrlProperty = BindableProperty.Create(
propertyName: "Url",
returnType: typeof(string),
declaringType: typeof(MyWebView),
defaultValue: default(string));
public string Url
{
get { return (string)GetValue(UrlProperty); }
set { SetValue(UrlProperty, value); }
}
}
In the above 2 cases, I need to play the video without full-screen mode on the iPhone.

You could set AllowsInlineMediaPlayback as True in Custom Renderer
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace CustomWebview.iOS
{
public class MyWebViewRenderer : ViewRenderer<MyWebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<MyWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
WKWebViewConfiguration configuration = new WKWebViewConfiguration();
configuration.AllowsInlineMediaPlayback = true;
wkWebView = new WKWebView(CGRect.Empty, configuration);
if (Element.Url != null)
{
wkWebView.LoadRequest(new NSUrlRequest(new NSUrl((Element).Url)));
}
SetNativeControl(wkWebView);
}
if (e.NewElement != null)
{
CallVideo();
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals(nameof(Element.Url)))
{
wkWebView.LoadRequest(new NSUrlRequest(new NSUrl((Element).Url)));
}
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
Control.Frame = rect;
}
}
}
Added an if statement to exclude the null condition. And then load the URL when you set it in Forms. OnElementPropertyChanged will be called when the property of webview has been changed. So when you set its URL in forms, we could load requests in this method.

Related

How to trigger a button click for deviceorientation in WebGL

I have a button to open the browser to fullscreen mode. This is the code:
private void ResizeButton_OnClick (UberButton obj)
{
if (!Screen.fullScreen)
Screen.fullScreen = true;
else
Screen.fullScreen = false;
}
How can I implement automatic button pressing when the screen orientation changes
private void Update()
{
if (Input.deviceOrientation == DeviceOrientation.LandscapeLeft)
{
// ...
}
}

requestReview() deprecated in iOS 14, Alternative for xamarin.forms?

I'm using
SKStoreReviewController.RequestReview ();
in a dependency service for Xamarin.Forms. However this is now deprecated from iOS 14. And I want to know how to integrate with the new
UIWindowScene
requestReview(in windowScene: UIWindowScene)
in Xamarin.Forms
First, you can try to add SKStoreReviewController.RequestReview(Window.WindowScene) in the FinishedLaunching method of your xxx.ios->AppDelegate.cs; start the project to see if it is correct.
If the above method goes wrong, using DependencyService is the right way to go.
Here is the interface code:
public interface MyInterface
{
void RequestReview();
}
Here is the implementation method of the interface in ios:
[assembly: Dependency(typeof(MyInterfaceImpl))]
namespace App19.iOS
{
public class MyInterfaceImpl : MyInterface
{
public void RequestReview()
{
var myv = UIDevice.CurrentDevice.CheckSystemVersion(14, 0);
if (myv)
{
UIWindow window = UIApplication.SharedApplication.Delegate.GetWindow();
SKStoreReviewController.RequestReview(window.WindowScene);
}
else
{
SKStoreReviewController.RequestReview();
}
}
}
}
You can call it in the OnStart method inside APP.xaml.cs:
protected override void OnStart()
{
if (Device.RuntimePlatform == Device.iOS)
{
DependencyService.Get<IReviewService>().RequestReview();
}
}
I might have a solution:
using StoreKit;
using UIKit;
public void RequestReview(){
var scene = UIApplication.SharedApplication.KeyWindow.WindowScene;
if (scene is null)
{
//handle the scene being null here
return;
}
SKStoreReviewController.RequestReview(scene);
}
I've found multiple ways of getting the current scene and they both worked when I tested them:
var scene = UIApplication.SharedApplication.KeyWindow.WindowScene;
var alsoScene = UIApplication.SharedApplication.Delegate.GetWindow()?.WindowScene;
You can read more about the difference between the two in this issue
The complete solution where you check the iOS version in order to call the right thing might look like this
using StoreKit;
using UIKit;
public void RequestReview()
{
var isIos14OrAbove = UIDevice.CurrentDevice.CheckSystemVersion(14, 0);
if (isIos14OrAbove)
{
var scene = UIApplication.SharedApplication.KeyWindow.WindowScene;
if (scene is null)
{
//handle the scene being null here
return;
}
SKStoreReviewController.RequestReview(scene);
}
else
{
SKStoreReviewController.RequestReview();
}
}
Hope this helps.

Unity Banner is not showing

My Banner Ad does show in test mode but without testmode not.
I used a code template from the unity website.
I also asked the unity ads support but they couldn't find the error.
they send me a video of my application,and in this video the banner ad worked.
Here is my code:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Advertisements;
public class newadsystem : MonoBehaviour
{
// For the purpose of this example, these buttons are for functionality testing:
[SerializeField] Button _loadBannerButton;
[SerializeField] Button _showBannerButton;
[SerializeField] Button _hideBannerButton;
[SerializeField] BannerPosition _bannerPosition = BannerPosition.BOTTOM_CENTER;
[SerializeField] public string _androidAdUnitId = "Banner_Android";
[SerializeField] string _iOsAdUnitId = "Banner_iOS";
public string _adUnitId = "Banner_Android";
void Start()
{
Advertisement.Initialize("4395157",false,true);
// Disable the button until an ad is ready to show:
_showBannerButton.interactable = true;
_hideBannerButton.interactable = true;
// Set the banner position:
Advertisement.Banner.SetPosition(_bannerPosition);
// Configure the Load Banner button to call the LoadBanner() method when clicked:
_loadBannerButton.onClick.AddListener(LoadBanner);
_loadBannerButton.interactable = true;
}
// Implement a method to call when the Load Banner button is clicked:
public void LoadBanner()
{
// Set up options to notify the SDK of load events:
BannerLoadOptions options = new BannerLoadOptions
{
loadCallback = OnBannerLoaded,
errorCallback = OnBannerError
};
// Load the Ad Unit with banner content:
Advertisement.Initialize("4395157", false, true);
Advertisement.Banner.Load(_adUnitId, options);
Advertisement.Initialize("4395157", false, true);
}
// Implement code to execute when the loadCallback event triggers:
void OnBannerLoaded()
{
Debug.Log("Banner loaded");
// Configure the Show Banner button to call the ShowBannerAd() method when clicked:
_showBannerButton.onClick.AddListener(ShowBannerAd);
// Configure the Hide Banner button to call the HideBannerAd() method when clicked:
_hideBannerButton.onClick.AddListener(HideBannerAd);
// Enable both buttons:
_showBannerButton.interactable = true;
_hideBannerButton.interactable = true;
}
// Implement code to execute when the load errorCallback event triggers:
void OnBannerError(string message)
{
Debug.Log($"Banner Error: {message}");
// Optionally execute additional code, such as attempting to load another ad.
}
// Implement a method to call when the Show Banner button is clicked:
void ShowBannerAd()
{
// Set up options to notify the SDK of show events:
BannerOptions options = new BannerOptions
{
clickCallback = OnBannerClicked,
hideCallback = OnBannerHidden,
showCallback = OnBannerShown
};
// Show the loaded Banner Ad Unit:
Advertisement.Initialize("4395157", false, true);
Advertisement.Banner.Show(_adUnitId, options);
}
// Implement a method to call when the Hide Banner button is clicked:
void HideBannerAd()
{
// Hide the banner:
Advertisement.Banner.Hide();
}
void OnBannerClicked()
{
Debug.Log("Banner Clicked!");
}
void OnBannerShown()
{
Debug.Log("Banner Shown!");
}
void OnBannerHidden()
{
Debug.Log("Banner Hidden");
}
void OnDestroy()
{
// Clean up the listeners:
_loadBannerButton.onClick.RemoveAllListeners();
_showBannerButton.onClick.RemoveAllListeners();
_hideBannerButton.onClick.RemoveAllListeners();
}
}
I looked into the android device log and there was: "Unity : Banner Error: UnityAds is not initialized."
but i call several times the initialize function.
PS: i am not very good at english.
Have a look at Start (), your code:
Advertisement.Initialize("4395157",false,true);
// Disable the button until an ad is ready to show:
_showBannerButton.interactable = true;
_hideBannerButton.interactable = true;
And then at OnBannerLoaded ()
// Enable both buttons:
_showBannerButton.interactable = true;
_hideBannerButton.interactable = true;
But those button are already interactable = true.
Maybe you need to change Start () like this:
Advertisement.Initialize("4395157",false,true);
// Disable the button until an ad is ready to show:
_showBannerButton.interactable = false;
_hideBannerButton.interactable = false;
Update 1
Try to change your code the following way:
void Start()
{
_showBannerButton.interactable = false;
_hideBannerButton.interactable = false;
Advertisement.Initialize("4395157",false,true);
_loadBannerButton.onClick.AddListener(LoadBanner);
_showBannerButton.onClick.AddListener(ShowBannerAd);
_hideBannerButton.onClick.AddListener(HideBannerAd);
_loadBannerButton.interactable = true;
}
public void LoadBanner()
{
BannerLoadOptions options = new BannerLoadOptions
{
loadCallback = OnBannerLoaded,
errorCallback = OnBannerError
};
if (Advertisement.isInitialized) {
Advertisement.Banner.Load(_adUnitId, options);
} else Debug.LogWarning ("Adverisement not initialized! Try again later");
}
void OnBannerLoaded()
{
Debug.Log("Banner loaded");
BannerOptions options = new BannerOptions
{
clickCallback = OnBannerClicked,
hideCallback = OnBannerHidden,
showCallback = OnBannerShown
};
Advertisement.Banner.SetPosition(_bannerPosition);
_showBannerButton.interactable = true;
_hideBannerButton.interactable = true;
}
void ShowBannerAd()
{
Advertisement.Banner.Show(_adUnitId, options);
}

monotouch dispose UIWebView

Using a UIWebView in my application and I cant seem to release the memory it's using.
I have a UIButton which loads a view controller which holds the UIWebView.
When the webView is loaded the Real Memory (checking it using Instruments) rises but doesn't get lower after my attempts to release it.
When the button is pressed:
if (childBroswer != null)
{
childBroswer.Dispose();
childBroswer = null;
}
childBroswer = new ChildBrowser(url);
AppDelegate d = (AppDelegate)UIApplication.SharedApplication.Delegate;
if ( d.rootNavigationController.RespondsToSelector(
new MonoTouch.ObjCRuntime.Selector("presentViewController:animated:completion:")))
{
d.rootNavigationController.PresentViewController(childBroswer, true, null);
}
else
{
d.rootNavigationController.PresentModalViewController(childBroswer, true);
}
Child browser class:
public partial class ChildBrowser : UIViewController
{
public string _url {get;set;}
UIActivityIndicatorView activityIndicator;
UIWebView webBrowser;
NSUrl nsURL;
NSUrlRequest nsURLRequest;
public ChildBrowser (string url) : base ("ChildBrowser", null)
{
nsURL = new NSUrl(url);
nsURLRequest = new NSUrlRequest(nsURL);
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
if (webBrowser == null)
{
webBrowser = new UIWebView(new RectangleF(0,41,320,380));
}
this.Add(webBrowser);
webBrowser.LoadFinished += (object sender, EventArgs e) => {
activityIndicator.StopAnimating();
} ;
webBrowser.LoadStarted += (object sender, EventArgs e) => {
if (activityIndicator == null)
{
activityIndicator = new UIActivityIndicatorView(new RectangleF(UIScreen.MainScreen.Bounds.Width / 2 - 50,
UIScreen.MainScreen.Bounds.Height / 2 - 30,100,100));
activityIndicator.Color = UIColor.Black;
}
activityIndicator.StartAnimating();
this.Add(activityIndicator);
} ;
webBrowser.LoadHtmlString("<html><head></head><body></body></html>",null); //stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML = \"\";"];
webBrowser.LoadRequest(nsURLRequest);
closeBrowser.TouchUpInside += handleClose;
// Perform any additional setup after loading the view, typically from a nib.
}
private void handleClose(object sender, EventArgs e)
{
webBrowser.Delegate = null;
webBrowser.StopLoading();
webBrowser.Dispose();
DismissViewController(true,delegate {
closeBrowser.TouchUpInside -= handleClose;
webBrowser.RemoveFromSuperview();
this.Dispose();
} );
}
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(true);
//webBrowser.RemoveFromSuperview();
}
public void webViewDidFinishLoad(UIWebView webView)
{
//string u = "";
}
protected override void Dispose(bool disposing)
{
ReleaseDesignerOutlets();
base.Dispose(disposing);
}
What am i missing?
Thank you!
Memory for native objects is not reclaimed when you call Dispose. Calling Dispose only drops the managed reference - but the ObjC runtime (reference counted) won't free the object until there's no native reference as well. See this Q&A for more details...
This means that code such as:
this.Add(webBrowser);
will create such a native reference and is likely (i.e. if not removed elsewhere) to keep the webBrowser instance alive as long as this is alive. If you keep Adding then you memory usage will keep growing.
I'm the OP - It seems that releasing the memory usage of UIWebView is quite hard, even when doing so in Objective-C.
What I have eventually done, which didn't solve the problem but improved the memory release is adding the following lines when closing the UIWebView:
NSUrlCache.SharedCache.RemoveAllCachedResponses();
NSUrlCache.SharedCache.DiskCapacity = 0;
NSUrlCache.SharedCache.MemoryCapacity = 0;
webView.LoadHtmlString("",null);
webView.EvaluateJavascript("var body=document.getElementsByTagName('body')[0];body.style.backgroundColor=(body.style.backgroundColor=='')?'white':'';");
webView.EvaluateJavascript("document.open();document.close()");
webView.StopLoading();
webView.Delegate = null;
webView.RemoveFromSuperview();
webView.Dispose();

UIWebview does not get cookies

My UIWebview is not saving cookies at all. It is stuck in cookieless mode and as a result, the webpage is putting the cookie information in the url instead.
Here is what I am doing. I have a singleton for my UIWebview and 4 UITabBar buttons on the bottom. Each tabbar button takes the user to a different page on the site. Now, when the user is navigating the site through the webview itself, everything is fine and session persists. But the second a user clicks on a tabbar button, the session gets reset.
I even set NSHttpCookieStorage to always accept cookies. Still no go.
Here is the code for my singleton for UIWebview and NSMutableUrlRequest
public static UIWebView instance;
public static NSMutableUrlRequest urlRequest;
public static NSUrlConnection connection;
public static NSHttpCookieStorage cookie;
static bool TokenSent = false;
public UIWebViewSingleton () {}
public static UIWebView Instance
{
get
{
if (instance == null)
{
Debugger.Debug ("new uiwebview created");
cookie = NSHttpCookieStorage.SharedStorage;
cookie.AcceptPolicy = NSHttpCookieAcceptPolicy.Always;
connection = new NSUrlConnection();
instance = new UIWebView(new RectangleF(0f, 0f, 320f, 416f));
instance.ScalesPageToFit = true;
instance.LoadStarted += delegate {
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
};
instance.LoadFinished += delegate {
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = false;
AcquireUserId();
};
instance.MultipleTouchEnabled = false;
}
return instance;
}
}
public static NSMutableUrlRequest UrlRequest
{
get
{
if (urlRequest == null)
{
urlRequest = new NSMutableUrlRequest();
}
return urlRequest;
}
}
This is how I change to a page based on which button was pressed. The back button is working fine.
case BTN_BACK:
btn_ret.TouchUpInside += delegate(object sender, EventArgs e) {
UIWebViewSingleton.Instance.GoBack();
};
break;
case BTN_GUIDE:
btn_ret.TouchUpInside += delegate(object sender, EventArgs e) {
UIWebViewSingleton.UrlRequest.Url = new NSUrl(StaticFileNames.GuideUrl);
UIWebViewSingleton.Instance.LoadRequest (UIWebViewSingleton.UrlRequest);
};
break;
case BTN_HOME:
btn_ret.TouchUpInside += delegate(object sender, EventArgs e) {
UIWebViewSingleton.UrlRequest.Url = new NSUrl(StaticFileNames.BaseUrl);
UIWebViewSingleton.Instance.LoadRequest (UIWebViewSingleton.UrlRequest);
};
break;
Does anyone have any ideas as to why my UIWebView is not accepting cookies? I'm still confused about NSHttpCookieStorage and if I'm using that correctly.
Thanks a lot.
I went with this work-around which was sufficient.
Since the cookie is in the url, I just parse it out and put programmatically put it into the urls that the tabbar buttons point to. Problem solved.