Is it Possible to Keep WebView Audio Running in Background on Android? - c#

Is it possible to keep audio from a WebView, in particular, an embedded Webtorrent client (which plays video), running in the background on android? I've seen conflicting answers on this, and I'm curious what you guys know about the topic. I've seen some confirmed answers on ways to do it in android studio but not seen any for Xamarin.
I've been told that the WebView is considered a UI element; therefore, this makes it impossible to keep the video/audio running while in the background. So if that's the case, do you think with some clever coding I could override the android OS to fool it into thinking that the WebView is still in the foreground?
I know that it's possible to keep the audio running using MediaPlayer, if for example say, you're playing an MP3.. So another possibility might be using a service to maintain audio focus; but then, would the video stop playing (seeing as how that doesn't fix WebView being a UI element)?
One other possibility would be porting the entire app into a service.. but I'm not sure if that's possible. If I get an answer that it is, I'll do the work to make it happen.
I'm not looking for you guys to do the coding; I'm just looking for guidance on which method (if any) would be possible/plausible/most effective.
and here is some sample code I'm currently using to construct my WebView (not sure if that matters)
//what's on
[Activity]
//this class should be an aggregate subscription feed
public class WhatsOnActivity : Activity
{
public override void OnBackPressed()
{
WebView whatsOnWebView = FindViewById<WebView>(Resource.Id.webViewWhatsOn);
whatsOnWebView.GoBack();
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.whatsOn);
//declare webview and tell our code where to find the XAML resource
WebView whatsOnWebView = FindViewById<WebView>(Resource.Id.webViewWhatsOn);
whatsOnWebView.SetBackgroundColor(Android.Graphics.Color.Green);
//set the webview client
whatsOnWebView.SetWebViewClient(new WebViewClient());
//load the 'whats on' url, will need webscript for curated subscribed feed
whatsOnWebView.LoadUrl("https://www.bitchute.com/#listing-subscribed");
//enable javascript in our webview
whatsOnWebView.Settings.JavaScriptEnabled = true;
//zoom control on? This should perhaps be disabled for consistency?
//we will leave it on for now
whatsOnWebView.Settings.BuiltInZoomControls = true;
whatsOnWebView.Settings.SetSupportZoom(true);
//scrollbarsdisabled
// subWebView.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
whatsOnWebView.ScrollbarFadingEnabled = false;
}
}
EDIT: Also, my opensource project can be found here
https://github.com/hexag0d/bitchute_mobile_android_a2
Thanks, in advance. =]

I think it is quite late to answer this question, but the project I am working on is similar to this one.
I am currently working on this project by calling Activity with WebView through Foreground Service.
This is the code that calls Activity with Webview in Service.
Put this in the onStartCommand() of the Service.
Context context = getApplicationContext();
Intent dialogIntent = new Intent(context, WebViewActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);

Related

How to close app after 3 wrong login using sqlite tries in xamarin? [duplicate]

How to terminate a Xamarin application from any of the activities?
I have tried both System.Environment.Exit(0) and System.Environment.Exit(1) as well as Finish() and killing all the activities.
It still opens one blank page with default activity name and a black screen.
Is there any specific solution for this?
If you are using Xamarin.Forms create a Dependency Service.
Interface
public interface ICloseApplication
{
void closeApplication();
}
Android : Using FinishAffinity() won't restart your activity. It will simply close the application.
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
var activity = (Activity)Forms.Context;
activity.FinishAffinity();
}
}
IOS : As already suggested above.
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
Thread.CurrentThread.Abort();
}
}
UWP
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
Application.Current.Exit();
}
}
Usage in Xamarin Forms
var closer = DependencyService.Get<ICloseApplication>();
closer?.closeApplication();
A simple way to make it work cross platform is by this command:
System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
Got it from this link.
EDIT: After using it for a while, I discovered that .CloseMainWindow() don't kill the application, only Closes it (well, thats obvious). If you want to terminate the app (kill), you shoud use the following:
System.Diagnostics.Process.GetCurrentProcess().Kill();
For Android, you can do
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
iOS explicitly does not provide any API for existing an App. Only the OS can close an App.
For iOS, you can use this code:
Thread.CurrentThread.Abort();
For Android, as #Jason mentioned here:
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
System.Environment.Exit(0);
Works for me.
In your activity, use this code
this.FinishAffinity();
I tried this code
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
var result = await DisplayAlert("", "Would you like to exit from application?", "Yes", "No");
if (result)
{
if (Device.OS == TargetPlatform.Android)
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
else if (Device.OS == TargetPlatform.iOS)
{
Thread.CurrentThread.Abort();
}
}
});
return true;
}
In this, iOS and Android application close when a user chooses to terminate the application. Maybe it helps you.
A simple all-in-one combination of the previous answers, instead of the interface/dependency:
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
var result = await this.DisplayAlert("Alert!", "want to exit?", "Yes", "No");
if (result)
{
#if __ANDROID__
var activity = (Android.App.Activity)Forms.Context;
activity.FinishAffinity();
#endif
#if __IOS__
Thread.CurrentThread.Abort();
#endif
}
});
return true;
}
System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
System.Diagnostics.Process.GetCurrentProcess().Kill();
None of the methods above helped my Xamarin Android app to completely shut down. I tried to close it from Activity B, having Activity A also open under it.
A clever guy left a trick here.
First call FinishAffinity() in Activity B (closes both activities,
however, the app is still alive in the background)
Then call JavaSystem.Exit(0) to kill the background app (I think it can be replaced with Android.OS.Process.KillProcess(Android.OS.Process.MyPid()); or System.Diagnostics.Process.GetCurrentProcess().Kill();)
My method to close the app:
private void CloseBtn_Click(object sender, EventArgs e){
FinishAffinity();
JavaSystem.Exit(0);
}
As your original question mentions activities, your question is specifically for Android, you should probably update the question title with that in mind to avoid people looking for a cross-platform solution coming here.
For iOS and Android (say in Xamarin Forms) you can just throw an exception, which while being the "heavy handed" approach, will do the job:
throw new Exception();
As this isn't the best user experience and you may only want to use this for iOS because on Android, you are likely to get a system popup telling you the app crashed. However, unlike other iOS methods like calling exit(0) or calling private iOS methods like "terminateWithSuccess" via a selector, it shouldn't fail app store validation purely based on how you do it. They may still fail you because your app tries to terminate itself.
You may want to implement something different specifically for Android, in which case Jason's answer is sufficient, again if not a little on the nose i.e. using this approach may not allow your app to clean itself up:
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
Either way, you should really question why you need to provide this option. Unlike desktop applications where closing an application is needed because apps reside inside windows which by design allow multi-tasking and are not task orientated, mobile platforms are primarily designed for users to focus on one task at a time. Once the user is finished the task, they should decide to exit this task by clicking the home button, back button or change app (task) button. This really applies to all platforms.
None of these work with Android 8. They all left the app in the background.
I can prove this by pressing the close all button and the app is still there.
For my testing I used a brand new simple Android app and tried all of your answers.
Application.Quit();
I'm assuming you are using C#
Call
public void Quit ();
This will quit the application the correct way without it "crashing".

How to make a listener of a service on android

I have this code to check if a service is active, but I would like to know if there is any way for an EditText to show the status of the service, without making this query per second, or in a separate thread, or linking it in some way? that it is possible to detect if the service stopped
private bool MiServicioEstaCorriendo(Class #class, Context contexto)
{
ActivityManager manager = (ActivityManager)contexto.GetSystemService(Context.ActivityService);
foreach (ActivityManager.RunningServiceInfo service in manager.GetRunningServices(Integer.MaxValue))
{
if (#class.Name.Equals(service.Service.ClassName))
{
Log.Info(typeof(BroadcastGps).Name, "MiServcicioEstaCorriendo: true");
return true;
}
}
Log.Info(typeof(BroadcastGps).Name, "MiServcicioEstaCorriendo: false");
return false;
}
You are basically in need of a way to pass events/messages among classes within your application. So this question probably goes down to Android & C# implementation of such a pattern. Xamarin.Forms has a MessagingCenter class, but since you are using Xamarin.Native, you would have to create something yourself
There's nothing actually already baked in to Android or C#, but so you can implement one of the most common ways to let a class spread an event/message using the "Listener" (term used in Android) or "Delegate" (term used in C#) technique.
There are frameworks too like PubNub that you can use as Nuget packages that simplify everything for you.
Some more resources to understand the concept: Wikipedia, IBM.
And Some Android resources: Handlers, AsyncTasks, Parcelables.
Don't forget that your event to update your EditText may not be fired on the Main UIThread so you won't be able to see the changes unless you force that update line to be Run on UI Thread.

Xamarin iOS 10 landscape

My goal is to force landscape orientation on a single view controller, not the entire app (to be exact: I want to make my camera view controller to be landscape only)
I've been running into the issue not being able to force landscape on iOS 10 devices with Xamarin.iOS.
I've got it working on iOS 9 or lower by overriding the following methods in the view controller that is supposed to be in landscape only. However, these methods don't seem to be called on iOS 10.
public override bool ShouldAutorotate()
{
return true;
}
public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
{
return UIInterfaceOrientation.LandscapeLeft;
}
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{
return UIInterfaceOrientationMask.Landscape;
}
I also tested calling this method from ViewDidLoad (I'm not using this line anymore and can't tell if it has any effect)
//AppDelegate
public void ChangeOri()
{
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeLeft), new NSString("orientation"));
}
Any suggestions on a possible workaround?
I finally found an answer, it has nothing to do with iOS 10 itself.
I had the issue on iPad devices. iPads with iOS9 or higher have received a new function: "Multitasking". Refer to this thread to learn more about.
The crux is, when your app is set to be multitasking you can no longer change orientations from code. You have to enable fullscreen mode for the whole app to make the lines of code be called that I posted in my question above.
Set in your plist: UIRequiresFullScreen to true to do so.

Where to initialize PCL instanced in a Xamarin.iOS app?

I'm working on a Xamarin application, which I will at first have working on iOS, but plan to later expand to Android and other mobile platforms.
As such, I'm trying to keep as much common code in PCLs as possible.
My question: what is the best practise - in Xamarin.iOS for now - to initialize any dependent PCL code?
For now I have it in the RootViewController inside ViewDidLoad()
public override void ViewDidLoad()
{
base.ViewDidLoad();
_engine = new MyEngine();
View = new MainView(_engine);
}
Is this the right spot? I'd considered putting it in the ctor for the RootViewController, but there's a fair bit going on in the initialization code, which thus ran against "don't put heavy duty init code into a constructor".
Things that happen are:
Load app settings
If app is run for first time ever, load basic defaults
Initialise other PCL libraries, such as a TextToSpeech module, a state engine (hence the name of the class above), etc
Prepare a data grid based on XML or JSON input
Alternately, I though it should possibly go into the AppDelegate section, but that didn't sound right.
I'm still fairly new to mobile app dev in general and Xamarin in specific, though I've done C# native code for Windows for years. I just want to make sure I follow best practises, but there doesn't seem to be a "thou shalt" in this case.
Edit: I've extracted the solution based on #wishmaster's suggestions.
For iOS the Appdelegate method is the best place for initialization code. The appdelegate also provides multiple delegate methods to give you feedback on application lifecyle events such as the method "DidFinishLauchingWithOptions"
. if you have a lot of data to download or long running tasks that your app depends on I would suggest you take a look backgrounding for iOS.
A technique I have also used is for my first viewcontroller on IOS (or activity on Android) to display a splash screen and a loading indicator while i run some code to refresh the cache.
Using #wishmaster's pointers, this solution works like a charm:
In AppDelegate.cs
// in the global section put any data you may make available elsewhere
private var _engine;
public Engine => _engine;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
/*
* Do whatever init needs to happen here, if you need to make this
* available elsewhere, ensure you have properties or accessors,
* as above.
*/
_engine = new MyEngine();
return true;
}
Then in RootViewController.cs using a similar approach to these examples in Obc-C or Swift you can access the information through a property pointing at the AppDelegate.
var myappdelegate = UIApplication.SharedApplication.Delegate as AppDelegate;
var engine = myappdelegate.Engine;
View = new MainView(engine);
The result resulted in a snappier start up of the application, because the initialisation now happens during the splash screen and no longer between splash screen and appearance of the UI.

Simple Alert in Android for Unity Plugin

I'm trying to create an Android Plugin for Unity, and it's going fine as long as i don't need the current context. But if i try to open a simple alert box, the app crashes. Anyone any idea what i am doing wrong? it seems not so hard...
Code in Java:
public static void openAlert() {
new AlertDialog.Builder(UnityPlayer.currentActivity).setTitle("Test").setMessage("This is an alert box!").setNeutralButton("Ok", null).show();
}
from unity, i'm doing the following (c#):
using (AndroidJavaClass myUnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
using (AndroidJavaObject obj_Activity = myUnityPlayer.GetStatic<AndroidJavaObject>("currentActivity")) {
AndroidJavaClass myActivity = new AndroidJavaClass("com.bundlename.appname.SampleClass");
myActivity.CallStatic("openAlert");
}
}
Since for some reason i don't get the crash messages from the device, it's a blind flight. I am new to c# and java development so excuse me if this is a stupid question.
Best
Wolfgang
First, anything you do that will modify the User Interface, such as Messages, Dialogs, Labels ... etc. should only be done from the main thread.
I dont know where the call your making is coming from, but if its not the main thread you may run into issues like this.
This video set helped me to build my android plugins.
Here is the playlist, he goes through the whole gambit. Ill start you off on the first android video.
http://www.youtube.com/watch?v=s1Mle2ERiuQ&list=PLf8PfKIJPGkjhMgylU87G5A0JLMSy_8ad
There are 3 android videos and all the examples work, just watch them in high definition so you can read the code being typed.

Categories