Automatically open UWP app that launches on startup - unity3d

I am working on a UWP app generated by Unity. Following the documentation on StartUpTasks here I have set the app to launch at startup, however when it does it launches minimized in the taskbar. I need the app to be open when it launches, but do not know what to call and where to make this happen.
This is the code generated by Unity:
namespace UnityToUWPApp
{
class App : IFrameworkView, IFrameworkViewSource
{
private WinRTBridge.WinRTBridge m_Bridge;
private AppCallbacks m_AppCallbacks;
public App()
{
SetupOrientation();
m_AppCallbacks = new AppCallbacks();
}
public virtual void Initialize(CoreApplicationView applicationView)
{
applicationView.Activated += ApplicationView_Activated;
CoreApplication.Suspending += CoreApplication_Suspending;
// Setup scripting bridge
m_Bridge = new WinRTBridge.WinRTBridge();
m_AppCallbacks.SetBridge(m_Bridge);
m_AppCallbacks.SetCoreApplicationViewEvents(applicationView);
}
private void CoreApplication_Suspending(object sender, SuspendingEventArgs e)
{
}
private void ApplicationView_Activated(CoreApplicationView sender, IActivatedEventArgs args)
{
CoreWindow.GetForCurrentThread().Activate();
}
public void SetWindow(CoreWindow coreWindow)
{
m_AppCallbacks.SetCoreWindowEvents(coreWindow);
m_AppCallbacks.InitializeD3DWindow();
}
public void Load(string entryPoint)
{
}
public void Run()
{
m_AppCallbacks.Run();
}
public void Uninitialize()
{
}
[MTAThread]
static void Main(string[] args)
{
var app = new App();
CoreApplication.Run(app);
}
public IFrameworkView CreateView()
{
return this;
}
private void SetupOrientation()
{
Unity.UnityGenerated.SetupDisplay();
}
}
}
How can I ensure that when the app starts it is open and active?

UWP apps that are set as Startup task get launched as minimized/suspended by design. This is to ensure a good user experience for Store app by default and avoid having a ton of apps launch into the user's face on boot.
Classic Win32 apps as well as desktop bridge apps can continue to start in the foreground for backwards compat/consistency reasons.
To accomplish your goal, you can include a simple launcher Win32 exe in your package and set that as startup task. Then when it starts you just launch the UWP from there into the foreground. Note that doing this will require you to declare the "runFullTrust" capability, which will require an additional onboard review for the Microsoft Store.
To declare the Win32 exe as startup task, follow the "desktop bridge" section from this doc topic:
https://learn.microsoft.com/en-us/uwp/api/Windows.ApplicationModel.StartupTask

Related

Running code when splash screen is shown in an MAUI application

I want to run some code while the splash screen is shown in a MAUI application. The official documentation has only instruction about the image (so far).
I assume I need to do a solution for each platform. I have tried to follow the instruction for Xamarin on Android and getting pretty close. I have created this Activity:
[Activity(Theme = "#style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : MauiAppCompatActivity
{
static readonly string TAG = "X:" + typeof(SplashActivity).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
Log.Debug(TAG, "SplashActivity.OnCreate");
}
// Launches the startup task
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() => { SimulateStartup(); });
startupWork.Start();
}
// Simulates background work that happens behind the splash screen
async void SimulateStartup ()
{
Log.Debug(TAG, "Performing some startup work that takes a bit of time.");
await Task.Delay (3000); // Simulate a bit of startup work.
Log.Debug(TAG, "Startup work is finished - starting MainActivity.");
//StartActivity(new Intent(MainApplication.Context, typeof (MainActivity)));
}
}
My problem is that when SimulateStartup starts to run the UI is launching, despite MainActivity is never created.
In then end of MauiProgram.CreateMauiApp() I have added this:
var app = builder.Build();
Task.Run(async () =>
{
await Task.Delay(4000);
var bootstrap = app.Services.GetRequiredService<MyBootstrapService>();
await bootstrap.SetupAsync();
}).Wait();
return app;
It works on Android. In Windows there are no splash screen, so user will se nothing until the bootstrapping is ready.

How to create a background service in .NET Maui

I'm new to mobile app development and am learning .NET Maui. The app I'm creating needs to listen for Accelerometer events, and send a notification to a web service if the events meet certain criteria. The bit I'm struggling with is how to have the app run in the background, i.e. with no UI visible, without going to sleep, as I'd want the user to close the UI completely. So I'm thinking the app needs to run as some kind of service, with the option to show a UI when needed - how can this be done?
i know it's beign a while but will post an answer for future users!
First we need to understand that background services depends on which platform we use.(thanks Jason) And i will focus on ANDROID, based on Xamarin Documentation (thanks Eli), adapted to Maui.
Since we are working with ANDROID, on MauiProgram we will add the following:
/// Add dependecy injection to main page
builder.Services.AddSingleton<MainPage>();
#if ANDROID
builder.Services.AddTransient<IServiceTest, DemoServices>();
#endif
And we create our Interface for DI which provides us the methods to start and stop the foreground service
public interface IServiceTest
{
void Start();
void Stop();
}
Then, before platform code we need to add Android Permissions on AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Android Main Activity
public class MainActivity : MauiAppCompatActivity
{
//set an activity on main application to get the reference on the service
public static MainActivity ActivityCurrent { get; set; }
public MainActivity()
{
ActivityCurrent = this;
}
}
And Finally we create our Android foreground service. Check Comments Below. Also on xamarin docs, they show the different properties for notification Builder.
[Service]
public class DemoServices : Service, IServiceTest //we implement our service (IServiceTest) and use Android Native Service Class
{
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
[return: GeneratedEnum]//we catch the actions intents to know the state of the foreground service
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (intent.Action == "START_SERVICE")
{
RegisterNotification();//Proceed to notify
}
else if (intent.Action == "STOP_SERVICE")
{
StopForeground(true);//Stop the service
StopSelfResult(startId);
}
return StartCommandResult.NotSticky;
}
//Start and Stop Intents, set the actions for the MainActivity to get the state of the foreground service
//Setting one action to start and one action to stop the foreground service
public void Start()
{
Intent startService = new Intent(MainActivity.ActivityCurrent, typeof(DemoServices));
startService.SetAction("START_SERVICE");
MainActivity.ActivityCurrent.StartService(startService);
}
public void Stop()
{
Intent stopIntent = new Intent(MainActivity.ActivityCurrent, this.Class);
stopIntent.SetAction("STOP_SERVICE");
MainActivity.ActivityCurrent.StartService(stopIntent);
}
private void RegisterNotification()
{
NotificationChannel channel = new NotificationChannel("ServiceChannel", "ServiceDemo", NotificationImportance.Max);
NotificationManager manager = (NotificationManager)MainActivity.ActivityCurrent.GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(channel);
Notification notification = new Notification.Builder(this, "ServiceChannel")
.SetContentTitle("Service Working")
.SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
.SetOngoing(true)
.Build();
StartForeground(100, notification);
}
}
Now we have our foreground Service working on Android, that show a notification ("Service Working"). Every time it starts. I make a show message foreground service to see it better while testing, in your case it suppose to close the app if that's what you want, but the functioning it's the same.
So having our background service working only left a way to call it so on our main page (as example) i will do the following:
MainPage.xaml
<VerticalStackLayout>
<Label
Text="Welcome to .NET Multi-platform App UI"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="start Services"
Clicked="OnServiceStartClicked"
HorizontalOptions="Center" />
<Button Text="Stop Service" Clicked="Button_Clicked"></Button>
</VerticalStackLayout>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
IServiceTest Services;
public MainPage(IServiceTest Services_)
{
InitializeComponent();
ToggleAccelerometer();
Services = Services_;
}
//method to start manually foreground service
private void OnServiceStartClicked(object sender, EventArgs e)
{
Services.Start();
}
//method to stop manually foreground service
private void Button_Clicked(object sender, EventArgs e)
{
Services.Stop();
}
//method to work with accelerometer
public void ToggleAccelerometer()
{
if (Accelerometer.Default.IsSupported)
{
if (!Accelerometer.Default.IsMonitoring)
{
Accelerometer.Default.ReadingChanged += Accelerometer_ReadingChanged;
Accelerometer.Default.Start(SensorSpeed.UI);
}
else
{
Accelerometer.Default.Stop();
Accelerometer.Default.ReadingChanged -= Accelerometer_ReadingChanged;
}
}
}
//on accelerometer property change we call our service and it would send a message
private void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEventArgs e)
{
Services.Start(); //this will never stop until we made some logic here
}
}
It's a long Answer and it would be great to have more official documentation about this! Hope it helps! If anyone can provide more info about IOS, Windows, MacCatalyst would be awesome!

Google AdMob test ads not showing after building in Unity

I wanted to implement google ads into my unity app with the official package (version 5.4.0, unity version is 2019.4.14):
https://github.com/googleads/googleads-mobile-unity/releases
When I run the project in the editor, the test ad is displayed. But when I build the app and install it on my phone, it doesn't show anything (my WiFi connection is good and I have access to Google services).
My ad manager:
using System;
using System.Collections;
using UnityEngine;
using GoogleMobileAds.Api;
public class AdsManager : MonoBehaviour
{
private static readonly string appId = "ca-app-pub-3940256099942544/3419835294";
private static readonly string bannerId = "ca-app-pub-3940256099942544/6300978111";
private static readonly string interstitialId = "ca-app-pub-3940256099942544/1033173712";
private static readonly string rewardedId = "ca-app-pub-3940256099942544/5224354917";
private static readonly string rewardedInterstitialId = "ca-app-pub-3940256099942544/5354046379";
private static readonly string nativeId = "ca-app-pub-3940256099942544/2247696110";
private InterstitialAd interstitialAd;
void Start()
{
MobileAds.Initialize(InitializationStatus => {});
this.RequestInterstitial();
}
public AdRequest CreateAdRequest() {
return new AdRequest.Builder().Build();
}
public void RequestInterstitial() {
Debug.Log("Requesting interstitial ad");
if(this.interstitialAd != null) {
this.interstitialAd.Destroy();
};
this.interstitialAd = new InterstitialAd(interstitialId);
this.interstitialAd.OnAdClosed += HandleOnInterstitialAdClosed;
this.interstitialAd.LoadAd(this.CreateAdRequest());
ShowInterstitial();
}
public void ShowInterstitial() {
if(this.interstitialAd.IsLoaded()) {
this.interstitialAd.Show();
} else {
this.RequestInterstitial();
}
}
public void HandleOnInterstitialAdClosed(object sender, EventArgs args)
{
Debug.Log("Closed interstitial ad");
}
}
I tried using the Android LogCat but it didn't find any mention of "Requesting interstitial ad". I get this log in the editor though and the test ad is shown. Any idea what is the issue?
Thanks
1 - The editor always shows test ads, after all when you use the app on the editor, you are testing it.
2 - If you want to display test ads on the device where you have installed the app, there are two ways: the first is to define your device as a test device in AdMob, the second to use strings for test ad units (https: //developers.google.com/admob/unity/test-ads#android)
3 - If you want to view real ads instead (be careful, if you see too many ads that you publish yourself and / or click them, you may have invalid traffic problems, so it is always better to view them as test ads), the real ads come to the end of a process:
First you need to create the app with the official app ID and ad unit strings that you get from the AdMob page for your app. Then you have to upload the app to a supported store, then you have to connect the app of the store to the app on AdMob, then the AdMob team performs a review on your app to verify that you are in order at a legal and regulatory level. , and eventually you will have your real, monetizable ads.

Is there a way to have Eclipse flash its taskbar icon once a time consuming task finishes?

I often minimize Eclipse to read or work on something else for a few minutes while I wait for it to do something (e.g., run a large JUnit test suite, synchronize a huge number of files with a repo, run a long Ant build, etc.). I have to check back every 30 seconds or so to see if it's finished yet. I would like Eclipse to alert me, preferably by blinking its taskbar icon, after it finishes a time consuming operation. Are there any settings or plugins that can make this happen?
I believe is you have Mylyn installed, this should be enabled by default for Windows 7. See here and here. Regarding the post-build actions, I do not know of any existing Eclipse plugins that do this. However, I have not exhaustively searched the marketplace. However, this could be accomplished with existing Eclipse APIs but it would require someone to author a new Eclipse plugin.
The Eclipse Platform jobs framework has an API called IJobManager. A developer could write a new Eclipse plugin that could use this API to listen for job changes and do the following:
Create an eclipse plugin, register a listener to IJobManager on startup.
Once any interesting job is completed, it could fire off some external task/script using normal java process execution API in the JDK
This all could be accomplished in one Java file, probably less than 500 lines long.
You could use this template to setup a basic Eclipse plugin project including build system and have it built and ready to install into your existing Eclipse.
Update I just found a maven archetype for building eclipse plugins with tycho here. It would be my recommendation for someone new to building an eclipse feature/updatesite.
You can create a new plugin project and create this kind of functionality for yourself. The
IJobchangeListener from the Eclipse Jobs API is probably very interesting for you.
The IJobChangeListener is an interface where you can receive notifications for the different type of job states.
I have created a class called JobListener which adds the IJobchangeListener to the JobManager. With the action SampleAction you can register or unregister the listener. that means, if the listener is registered and your application is minimized you will be notified with a MessageDialog (no blinking taskbar).
I found a link where someone made his swing application blink. This functionality should be included in the method public void done(final IJobChangeEvent event). I haven't done this in my test class.
You can also get additional information about the Job with
event.getJob();
Here you are able to check the Job name:
String jobName = event.getJob().getName();
The name of the Job is human readable, for example "Collecting garbage", "Update for Decoration Completion", "Building workspace", etc.
The JobListener class.
/**
* A job listener which may be added to a job manager
*/
public class JobListener {
private MyJobListener listener = null;
private IWorkbenchWindow window = null;
private boolean active = false;
public JobListener(IWorkbenchWindow window) {
this.window = window;
}
/**
* register the job listener
*/
public void register() {
listener = new MyJobListener(window);
IJobManager jobMan = Job.getJobManager();
jobMan.addJobChangeListener(listener);
active = true;
}
/**
* unregister the job listener
*/
public void unregister() {
IJobManager jobMan = Job.getJobManager();
jobMan.removeJobChangeListener(listener);
active = false;
}
public boolean isActive() {
return active;
}
class MyJobListener implements IJobChangeListener {
private IWorkbenchWindow window;
public MyJobListener(IWorkbenchWindow window) {
this.window = window;
}
#Override
public void sleeping(IJobChangeEvent event) {
}
#Override
public void scheduled(IJobChangeEvent event) {
}
#Override
public void running(IJobChangeEvent event) {
}
#Override
public void done(final IJobChangeEvent event) {
window.getShell().getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
if(window.getShell().getMinimized()) {
MessageDialog.openInformation(
window.getShell(),
"Test",
"Job " + event.getJob().getName() + " done.");
}
}
});
}
#Override
public void awake(IJobChangeEvent event) {
}
#Override
public void aboutToRun(IJobChangeEvent event) {
System.out.println("About to run: " + event.getJob().getName());
}
}
}
I called this class from a class called SampleAction.java
public class SampleAction implements IWorkbenchWindowActionDelegate {
private IWorkbenchWindow window;
private JobListener listener;
/**
* The constructor.
*/
public SampleAction() {
}
public void run(IAction action) {
if(listener.isActive()) {
listener.unregister();
MessageDialog.openInformation(
window.getShell(),
"Lrt",
"Unregistered");
}
else {
listener.register();
MessageDialog.openInformation(
window.getShell(),
"Lrt",
"Registered");
}
}
public void selectionChanged(IAction action, ISelection selection) {
}
public void dispose() {
}
public void init(IWorkbenchWindow window) {
this.window = window;
this.listener = new JobListener(window);
}
You can get started with eclipse plugin development by creating a new plugin project:
File > New > Project > Plugin Project
I used the Hello World plugin project template to test the code above.

Intermittent NSTimer problem in Release mode on device

I am having a problem where most, but not all, of the time on my device my NSTimer action is not being called when compiled in Release mode. It's always fine in Debug mode on the device, and it's always fine in either mode in the simulator.
The only thing that's slightly unusual about this situation is that it's wrapped with another class to allow us to inject platform-specific implementations of things like timers at runtime, thinking forwards to monodroid etc. Nothing particularly unusual going on though.
Code:
using System;
using MonoTouch.Foundation;
namespace OurCompany.PlatformAbstraction.Ios
{
public class IosTimer : IPlatformTimer
{
private NSTimer backingTimer;
public double IntervalMs{get; set;}
public IosTimer(double intervalMS)
{
this.IntervalMs = intervalMS;
}
public event EventHandler Elapsed;
private void NsTimerElapsed()
{
if (Elapsed != null)
{
Elapsed(this, EventArgs.Empty);
}
}
public void Start ()
{
TimeSpan ts = TimeSpan.FromMilliseconds(this.IntervalMs);
this.backingTimer = NSTimer.CreateRepeatingScheduledTimer(ts, NsTimerElapsed);
}
public void Stop ()
{
this.backingTimer.Invalidate();
this.backingTimer = null;
}
}
}
Calling code:
private IosTimer t;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
t = new IosTimer(100);
t.Elapsed += UpdateLabel;
t.Start();
}
private void UpdateLabel(object sender, EventArgs e)
{
// not being called in Release mode on the phone
// works fine in Debug mode on the phone, works fine in both modes in the simulator
}
I'm also noticing general behaviour differences - where something works fine in the simulator but not on the device. Also slight behaviour changes given two identical deployments of the exact same code to the same device(!)
Posted this yesterday on the MonoTouch forums but it seems a bit quiet over there.
Thanks in advance.
Transpired this was threading related. Solved by using InvokeOnMainThread() in my Elapsed event handlers.