I am quite new at Unity and I am trying to create a Unity plugin for an Android library jar and I am facing the following issues:
I can't find a way to pass the back button event to Android library. It seems that Unity prevents this event to be passed to the library layer. What I have managed to do is to pass touch events to the activity on the Android side by setting the following line
<meta-data android:name="unityplayer.ForwardNativeEventsToDal vik" android:value="true" />
at <activity android:name="com.unity3d.player.UnityPlayerProxyActivity" ... > in the AndroidManifest
However I cannot pass the back button event in a way that I do not have to change the code in the library
What I do for now in my script is
public void Update() {
if(Input.GetKeyDown(KeyCode.Escape))
Application.Quit();
}
However I need the option to pass that back event that I capture, to the library and not handle it at the Unity layer.
Maybe somehow like this.
myActivity.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
or this
myActivity.onBackPressed()
but through a C# script. How can I accomplish that within a script?
C# script:
void Update ()
{
if (Input.GetKeyUp (KeyCode.Escape)) {
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity");
jo.Call ("yourBackEventFunction");
}
}
And your Android lib
public class YourActivity extends
com.unity3d.player.UnityPlayerNativeActivity {
…
public void yourBackEventFunction() {
// Do something here
}
…
}
========================
Edit:
If you want to call onBackPressed, you can do so:
In YourActivity.java
#Override
public void onBackPressed() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(UnityPlayerNativeActivity.this,
"on Back Pressed", Toast.LENGTH_SHORT)
.show();
}
});
super.onBackPressed();
}
And in C# script:
void Update ()
{
if (Input.GetKeyUp (KeyCode.Escape)) {
Debug.Log ("onResume Received");
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity");
jo.Call ("onBackPressed");
}
}
Or inside YourActivity you can:
Create your YourActivity Extends UnityPlayerNativeActivty
Include your Jar lib and call the function you want.
Use C# script to call your Activity.
Note that in Unity, there is only 1 Activity, and it must be UnityPlayerNativeActivity OR it must be an Activity EXTENDS FROM UnityPlayerNativeActivity. You can not use any others activity from your Jar without extend from UnityPlayerNativeActivity.
If YourActivity class inside JAR extends UnityPlayerNativeActivity. and you don't want to change your JAR, then you create a new Activity class extends YourActivity. Create a new Jar + old Jar and make a new plugins.
========================
If you want to call a function directly from C# to Java class, you still can do it by using Android NDK to build an JNI lib
This sample demonstrates how Java code can be used to interact with
the Android OS and how C++ creates a bridge between C# and Java. The
scene in the package displays a button which when clicked fetches the
application cache directory, as defined by the Android OS. Please note
that you will need both the JDK and the Android NDK to compile the
plugins.
Reference here: http://docs.unity3d.com/Documentation/Manual/PluginsForAndroid.html
Example here: http://docs.unity3d.com/Documentation/Images/manual/AndroidJavaPlugin.zip
But I'm not sure if you can use your own Activity or not. And I recommend creating a new Activity Extends from UnityPlayerNativeActivty, because that way is more simple and unstandable than this way.
Br,
Frank
Related
This is pretty basic, but I'm not getting success on implementing it from the official Unity docs and YouTube video tutorials, so I asked.
I want to access methods from already made aar plug-in. Its checked as android plug-in by default. The plug-in has following code:
package alarm.company.com.unity;
public class myPlugin {
public String myTest(int i){
return "Hello your string number is: "+i;
}
}
the compiled aar plug-in is copied into the Unity folder.
Here's the c# code to access that method:
const string PluginName = "alarm.company.com.unity.myPlugin";
static AndroidJavaClass _pluginClass;
static AndroidJavaClass _pluginInstance;
public Text text;
// Start is called before the first frame update
void Start()
{
AndroidJavaClass plugin = new AndroidJavaClass(PluginName);
string s = plugin.CallStatic<string>("myTest", 9);
print(s);
text.text = s;
}
text is assigned and this script is put on the main camera. But I'm not getting any text back or the text object is not changed, while running in emulator. How can this be solved?
Unity Plugin development is a bit tricky to get setup at first but once you are able to it is pretty powerful.
Couple things.
1) You are using an AndroidJavaClass and trying to call a non static method in java. Your method in your plugin should be static if you are wanting to use that class.
2) Otherwise you will need to use an AndroidJavaObject to construct your class and then you should be able to call your function.
Hope this helps!
Example Using non Static Code:
Unity Code
using (AndroidJavaObject leetPlugin = new AndroidJavaObject("alarm.company.com.unity.myPlugin")){
string s = leetPlugin.Call("myTest", 9);
print(s);
text.text = s;
}
Android Code
public void myTest(int value) {
return "Your value is " + value;
}
Some advises when you work with plugins for unity:
Use gradle build system. It generates mainTemplate file in Plugins/Android. You can edit this file and set source java code to your java classes so you don't need to generate aar every time you want to build:
sourceSets
{
main
{
java
{
srcDirs = ['src']
srcDirs += ['E:/AndroidStudioProjects/PathToJavaClasses']
}
}
}
If you want to send something from java code to unity you should extend your activity from unity and call method UnitySendMessage
public class MyUnityPlayerActivity extends UnityPlayerActivity{
public void SendUnityMessage()
{
UnityPlayer.UnitySendMessage(UnityGameObjectName, UNITY_FUNCTION_NAME,
params);
}
}
I have an interface which is being implemented in some 20-30 classes. I have added a new new method to this interface.
Is there any shortcut in Android Studio to override this method in all the sub classes? Or do I need to manually go to all the classes and
implement manually?
If you use Java 8, then there's new interface feature called "default method" you may try using:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Ya, There is a way to achive such things by making your method DEFAULT inside your Interface.
For Example :
public interface oldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
" is added in interface");
}
}
The following class will compile successfully in Java JDK 8,
public class oldInterfaceImpl implements oldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
If you create an instance of oldInterfaceImpl:?
oldInterfaceImpl obj = new oldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
So I want to implement a twitter login into my Xamarin App, but if I follow the tutorial, the Portable App will not let me do this function:
var ui = auth.GetUI(this);
when auth is this:
var auth = new OAuth1Authenticator(
"DynVhdIjJDXXXXXXXXXXXXX",
"REvU5dCUQI4MvjV6aWwXXXXXXXXXXXXXXXXXXXXXXX",
new Uri("https://api.twitter.com/oauth/request_token"),
new Uri("https://api.twitter.com/oauth/authorize"),
new Uri("https://api.twitter.com/oauth/access_token"),
new Uri("http://twitter.com"));
So I need to add it into the Android Project, but how do I show the button from there?
Thanks for any help! :)
Based on OAuth1Authenticator and GetUI() I assume you use Xamarin.Auth.
Xamarin.Auth supports Xamarin.Forms with 2 implementations for GetUI(), so called Presenters (actually Dependency Service/Injection) and CustomRenderers. Presenters are more tested (thus more evidence of stabilty), but you can check the code in the repo.
Samples how to use Xamarin.Auth with the Xamarin.Forms:
https://github.com/moljac/Xamarin.Auth.Samples.NugetReferences/tree/master/Xamarin.Forms/Evolve16Labs
NOTE: this repo contains extracted samples from the main Xamarin.Auth repo, so the handling is easier and samples are updated more often.
Creating platform specific code in Xamarin?
You can use DependencyService to implement this function. Here is the document and example. The document explain that :
DependencyService allows apps to call into platform-specific functionality from shared code. This functionality enables Xamarin.Forms apps to do anything that a native app can do.
Create a ILogin interface in PCL :
public interface ILogin
{
void GetUI();
}
Implement the interface in Xamarin.Android :
[assembly: Xamarin.Forms.Dependency(typeof(TwitterLogin))]
namespace TwitterDemo.Droid
{
public class TwitterLogin : ILogin
{
public TwitterLogin()
{
}
public void GetUI()
{
var auth = new OAuth1Authenticator("DynVhdIjJDXXXXXXXXXXXXX", "REvU5dCUQI4MvjV6aWwXXXXXXXXXXXXXXXXXXXXXXX",
new Uri("https://api.twitter.com/oauth/request_token"),
new Uri("https://api.twitter.com/oauth/authorize"),
new Uri("https://api.twitter.com/oauth/access_token"),
new Uri("http://twitter.com"));
Intent intent = auth.GetUI(Android.App.Application.Context);
Forms.Context.StartActivity(intent);
}
}
}
Use it in Xamarin.Forms:
private void Button_Clicked(object sender, EventArgs e)
{
Xamarin.Forms.DependencyService.Register<ILogin>();
DependencyService.Get<ILogin>().GetUI();
}
I am trying to get ParseUI to work with my app.
I have imported the libs, sync with gradle and everything is workign fine. Till when I actually put the code for the activity to be initiated, I get error saying 'cannot resolve symbol build'.
public class Login_activity extends FragmentActivity //implements Validator.ValidationListener
{
ParseLoginBuilder builder = new ParseLoginBuilder(Login_activity.this);
Login_activity(builder.build(), 0);
Actual code that I am supposed to use according to Parse docs
ParseLoginBuilder builder = new ParseLoginBuilder(MyActivity.this);
startActivityForResult(builder.build(), 0);
EDIT:
This is the updated code
#Override
protected void onCreate(Bundle savedInstanceState) {
//
//super.onCreate(savedInstanceState);
ParseLoginBuilder builder = new ParseLoginBuilder(Login_activity.this);
startActivityForResult(builder.build(), 0);
}
This line
Login_activity(builder.build(), 0);
is not valid Java. Your are trying to call the name of the class as if it was a method. I am not sure what you are trying to do (invoke the constructor? - which would not make sense for an Activity), but this code is incorrect. If you meant to call startActivityForResult, then do so, instead of substituting startActivityForResult with your class name, because doing so makes no sense.
EDIT:
Furthermore, you are adding lines of code to be executed directly in the class body, as opposed to inside a method. In Java, a class body can only contain declarations (which may include statements as part of an assignment) or static blocks of code, all other code must be part of a method.
class MyClass {
... you can only have declarations and assignments here
public void someMethod() {
... actual code statements here
}
}
I wrote a Cordova plugin for Android to build a phonegap app with an HTML5 GUI.
I now want to have a native interface too and was wondering what is the neatest option to reuse my plugin for the native UI. Basically I would like to have two apps, one with a phonegap (HTML5) interface and one with a native Android interface, both of them using the Cordova plugin.
The plugin extends the CordovaPlugin class, so for this reason I don't know how to use it without calling the following method from the javascript in the WebView, as described here http://docs.phonegap.com/en/2.3.0/guide_plugin-development_android_index.md.html
exec(<successFunction>, <failFunction>, <service>, <action>, [<args>]);
I just want to call the native side of the plugin without going through a WebView:
#Override
public boolean execute(String action, JSONArray args,
CallbackContext callbackContext) throws JSONException { ... }
Provided that I could just adapt the code from the plugin fairly easily, I would like to find a method by which the plugin remains exactly the same for better decoupling of frontend/backend (I could change the code in one app without the need to replicate it in the other app).
Is this possible at all? I understand this is not the point of having a Cordova plugin, but I would like to find a way around it.
Thanks.
In my opinion you need to apply Facade pattern:
http://en.wikipedia.org/wiki/Facade_pattern
Simply extract your business logic from Cordova plugin to dedicated class called MyFacade and hide all your business logic behind.
The other way is to do something like this:
MyCordovaPlugin myPlugin = new MyCordovaPlugin();
myPlugin.execute("foo", new JSONArray(), new MyCallbackContext() {
#override
public void handlePluginResult(PluginResult pluginResult) {
//your code for handling plugin result for Android UI
}
}
Where MyCallbackContext implementation is:
public abstract class MyCallbackContext extends CallbackContext {
public MyCallbackContext() {
super(null, null);
}
public void sendPluginResult(PluginResult pluginResult) {
synchronized (this) {
if (finished) {
Log.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage());
return;
} else {
finished = !pluginResult.getKeepCallback();
}
}
handlePluginResult(pluginResult);
}
public abstract void handlePluginResult(PluginResult pluginResult);
}
This second way works only with current version of Cordova and is based on this source codes:
https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/api/CordovaPlugin.java
https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/api/CallbackContext.java