How to access android system settings with Unity in C# - c#

I'm making an app and need to be able to check if settings like : Bluetooth/Phone Rotation/Flashlight/Plane Mode/GPS/Phone Brightness/Silent Mode, are activated on an android phone.
I haven't found any way to do it within Unity, using C#. I found ways to do it using Xamarin but none of them work with Unity (or maybe I haven't done it right), the only way I found is using Java and making it into a plugin and call it in a C# script. But I can't find a clear way to make this work. If this is the only solution could you please explain how to do it, all the documentation I find is from old versions from 2014.
I think there is a simple solution for this but I simply can't find it. And the manifest part is not a problem, I'll add the permissions needed.

In Java the methods you want to call should be public or static, you must build your java source as a library (in build.gradle: apply plugin: 'com.android.library'), and add the .aar to Unity's Assets/Plugins/Android/ folder.
Then you can instantiate your plugin in Unity like so:
// this class string is the package at the top of your Java class extended with the class name, e.g.:
// package com.yourcompany.you.package;
string classString = "com.yourcompany.you.package.className";
// Get the class
var tempAjc = new AndroidJavaClass(classString);
// Here you can call a static method on the class that returns an instance of the class if you want to pass some parameters upon creation
_androidObject = tempAjc.CallStatic<AndroidJavaObject>("CreateInstance",
new object[] {arg1, arg2});
// non static call on your new instance
_androidObject.Call("PassingMoreStuff", initParam);
// if you want to return something from Java to Unity:
int javaVal = _androidObject.Call<int>(methodName, parameters);

Related

Can I check available storage in the Device on Xamarin Forms?

I am trying to make an app that requires that I frequently send recorded data to a firebase. When network goes out or battery is about to die, I am saving all of the data that wasn't stored into firebase locally. However, to do this I require about 20 MB of data (my data is pretty big). That being said, I want to find a way to check the available storage (and the battery if possible) to give the user a warning. Is this possible using Xamarin Forms? Also, is there a way that I can make this solution universal (i.e. I don't need a separate piece of code for iOS vs. Android)? (I am new to Xamarin and C#)
Use the following code to check the free size of a device:
For iOS:
NSFileManager.DefaultManager.GetFileSystemAttributes (Environment.GetFolderPath (Environment.SpecialFolder.Personal)).FreeSize;
For Android:
var freeExternalStorage = Android.OS.Environment.ExternalStorageDirectory.UsableSpace;
There is no universal option, but you can wrap it an interface like so and implement it on each project:
public interface IStorage
{
double GetRemainingStorage();
}
It would be great if a feature like this could be added in Xamarin.Essentials - there was a request on GitHub but it never really made it.
If there are any issues with the code - please tell me.
Hope this helped,
Instructions
Create an interface in your shared project titled IStorage.
In your Android project create a class titled AndroidStorageManager (you can name it however you would like). Make it so it extends IStorage. The method GetRemainingStorage() should be of return type double.
public class AndroidStorageManager : IStorage
{
public double GetRemainingStorage()
{
var freeExternalStorage = Android.OS.Environment.ExternalStorageDirectory.UsableSpace;
return freeExternalStorage;
}
}
For iOS
Create a class in your iOS project titled iOSStorageManager which extends IStorage:
public class iOSStorageManager : IStorage
{
public double GetRemainingStorage()
{
return NSFileManager.DefaultManager.GetFileSystemAttributes(Environment.GetFolderPath(Environment.SpecialFolder.Personal)).FreeSize;
}
}
In your Android implementation - add the following code above the namespace:
[assembly: Xamarin.Forms.Dependency(
typeof(AndroidStorageManager))]
For iOS:
[assembly: Xamarin.Forms.Dependency(
typeof(iOSStorageManager))]
To get the storage:
IStorage storageManager = DependencyService.Get<IStorage>();
double remaining = storageManager.GetRemainingStorage();
Hope this clarified things.

Xamarin PCL Refit 3.0.1 , Doesn't look like a Refit interface

I recently started working on a Xamarin Android/iOS project with a PCL class where I want to put all the logic in. Like my Refit interfaces, ReactiveUI ViewModels et cetera, but every time when trying to execute my code I get a error saying that my interface is not a Refit interface. Currently my interface looks like this.
public interface IMyApi
{
[Post("/authenticate")]
IObservable<Models.ApiResponses.AuthenticationResponse> SigninRaw([Body] JObject credentials);
[Get("/service")]
IObservable<Models.ApiResponses.MyListResponse> GetServiceListRaw();
[Get("/service/{id}/idstatus")]
IObservable<Models.ApiResponses.IdResponse> GetIdStatusRaw(string Id);
}
As far as I know this looks good and this also works when I'm trying to load this from a specific platform like iOS project. But when trying to do it from a PCL if fails! I have installed the Refit package in both of my platform specific project Android & iOS and I referenced a dll in the PCL, what did I miss?
If there is need for more information or you have any question, please do not hesitate to ask.
Well without further ado, thank you for reading and hopefully someone can assist me with this, because I starting to loose my mind the past couple of days.
Edit: added calling method.
Here I calling it from a ViewModel
var client = new HttpClient(NetCache.UserInitiated)
{
BaseAddress = new Uri("https://api.address.com")
};
var api = RestService.For<IMyApi>(client); <= here it crashes
var response = api.SigninRaw(token);
I've managed to track this down, there are actually a few issues at play. Fortunately there are ways to work around them.
The first problem is that the PCL interfaces aren't being detected in the first place. Refit runs a utility at compile time (InterfaceStubGenerator) which scans the subfolders for interface classes and generates implementation code for each one. These are all packed into an intermediate file called RestStubs.g.cs which gets included in with the assembly. This utility, however, is only run on the projects that Refit has been added to via nuget, and since that doesn't include PCL projects the interfaces in those projects never get processed. The solution is to call this utility manually in a pre-build step and include the generated file in each of the platform projects. Go to your PCL project's property settings and add the following to the pre-build steps:
..\..\..\..\packages\refit.3.0.1\tools\InterfaceStubGenerator.exe ..\..\..\ProjName.Droid\RefitStubs.cs ..\..\..\ProjName
..\..\..\..\packages\refit.3.0.1\tools\InterfaceStubGenerator.exe ..\..\..\ProjName.iOS\RefitStubs.cs ..\..\..\ProjName
That will generate RefitStubs.cs for your platform projects, so add each file to it's respective project.
Ordinarily that would be the end of it were it not for another problem. The RestService.For<> generics that you call to get the implementations make the assumption that the implementation classes reside in the same assembly as their corresponding interfaces. Obviously that isn't the case for PCL projects. To get around this you need to implement your own version of the RestService class, this will probably serve most of your needs:
public static class PclRestService
{
public static T For<T>(string hostUrl)
{
var className = "AutoGenerated" + typeof(T).Name;
var typeName = typeof(T).Namespace + "." + typeof(T).Name.Replace(typeof(T).Name, className);
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var generatedType = assembly.GetType(typeName);
var requestBuilder = RequestBuilder.ForType<T>();
var client = new HttpClient(new HttpClientHandler()) { BaseAddress = new Uri(hostUrl) };
return (T)Activator.CreateInstance(generatedType, client, requestBuilder);
}
}
You then call it like so:
var netService = PclRestService.For<IMyApi>("http://jsonplaceholder.typicode.com");
var result = await netService.GetDataOrSomething();
One last problem you may encounter is multiple declarations of the PreserveAttribute class, which is declared at the top of the stub files. So long as you don't add Refit interfaces to your platform projects this shouldn't happen, but if it does then you have 3 options:
modify the InterfaceStubGenerator utility to not create that code
write a pre-processor to strip that code out once it has been generated
go to Refit's "refit.targets" file and comment-out the line "<Exec Command="$(RefitExecCmd)" />
The Refit tools folder includes the template file used to generate stub files but for some strange reason it's ignored altogether and statically linked to the application, so editing it in the tools folder doesn't do anything at all.

How to make function "invisible" in a class library c#

I am creating a class library and have different functions inside. I also have a Console application that can access this functions once they reference the class library. I would like to know how to make a function "invisible" so the client won't be able to see it exist and they can only use it if they write it out perfectly.
I have this function in my class Library :
public string custommessage(string messagetosend)
{
string receivedmessage = CallServer(messagetosend);
return receivedmessage;
}
and basicly when I am in a different program referencing the library I dont want to see this function in my list of avaiable functions to chose from :
Append
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
to your method as an attribute. This will hide the function from intellisense.

How can I restrict access to members in an assembly from Roslyn script engine?

I am experimenting with the Roslyn script engine. Using the following code, I set up my script engine.
var csharpEngine = new ScriptEngine();
csharpEngine.AddReference("System");
csharpEngine.AddReference(this.GetType().Assembly.Location);
scriptSession = csharpEngine.CreateSession();
Then I execute a script with the following line:
scriptSession.Execute(script);
The script contains a very simple reference to a static function on a class in my assembly.
private string script =
#"using System;
using RoslynWindow;
Hello.SayHello();";
In the output window the function merely prints to the console. So I have shown I can call into a public static member of my assembly without passing a "HostObjectModel" to the script engine. I want to prevent this from happening. I'd like to be able to register only specific members (functions, variables or properties) to be accessed by the script engine, and no others.
Any idea how to accomplish this?
Traverse the AST with Roslyn to check if the script tries to call anything you don't allow.

Loading a script from a cs file and accessing host methods, properties etc?

I'm just having a play with Roslyn but unsure on how to do the following.
To keep this simple, lets say I have a host program which has a method like so
public void DisplayMessage(string message)
{
MessageBox.Show(message);
}
Can I then have a script file called MyScript.csx and then somewhere in the script have something like
void Main()
{
Host.DisplayMessage("I am a script");
}
Then I have the host load the file and execute it.
If this sort of thing can't be done, is there a scripting system/engine based on c# that can do it?
These are the requirements
Host application can load script from a file.
Script file is written in c# and so can be written using VS2010 with syntax etc
Script file can access host public methods, properties etc
I wrote an Introduction to the Roslyn scripting API that covers most of what you're asking. The ScriptEngine type also has a ExecuteFile method that would be useful for what you're trying to do.
Disclaimer: I work for Microsoft on the Roslyn project.
Yes, you can do what you want using Roslyn.
First, create a public Host class that has a public DisplayMessage method (or use a existing class). Then create ScriptEngine, specifying the assembly that contains Host as a reference. After that, you can call ExecuteFile() on your file, with the Host object as another parameter:
var engine = new ScriptEngine(references: new[] { typeof(Host).Assembly });
engine.ExecuteFile("MyScript.csx", new Host());
The script files doesn't need any Main() method, and you call the method on the host object directly:
DisplayMessage("I am a script");

Categories

Resources