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();
}
Related
I am rewriting my vanilla Xamarin app to use Prism Library.
The current app uses Azure ADB2C for authorisation using this framework.
Android needs to have its parent window set, which is achieved by adding this code into the MainActivity.cs of the Android project:
var authenticationService = DependencyService.Get<IAuthenticationService>();
authenticationService.SetParent(this);
This doesn't work for the Prism app, authenticationService is null. For the record, the DependencyService used here is Xamarin.Forms.DependencyService.
I also tried the example from the Prism docs and put this code into the AndroidInitializer:
public void RegisterTypes(IContainerRegistry container)
{
// Register any platform specific implementations
container.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>("B2CAuthenticationService");
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(this);
}
In this code, Container (which is a DryIoC Container) had no definition for Resolve.
For completeness, this is my App.cs RegisterTypes:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>();
...
...
}
There are a few wrong assumptions you're making here. To start you'll notice that IContainerRegistry specifically has the name Registry in it to imply we don't want you resolving types here. This is why you don't see the Resolve method on it but rather the IContainerProvider instance.
By design, Prism no longer works directly with the Xamarin.Forms DependencyService as this is a complete anti-pattern. That said if you follow the guidance for registering Platform Specific types you can see how to use the IPlatformInitializer to register platform specific types. It is important to realize here that the IPlatformInitializer is called before RegisterTypes is called in PrismApplication.
What I would suggest is to introduce a IParentWindowProvider like:
public interface IParentWindowProvider
{
object Parent { get; }
}
You can then implement this on Android like:
public class MainActivity : IPlatformInitializer, IParentWindowProvider
{
object IParentWindowProvider.Parent => this;
void IPlatformInitializer.RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterInstance<IParentWindowProvider>(this);
}
}
Then in your Application you might do something like:
protected override void OnInitialized()
{
if(Container.IsRegistered<IParentWindowProvider>())
{
var provider = Container.Resolve<IParentWindowProvider>();
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(provider.Parent);
}
}
For more info be sure to check out the relevant docs and sample
https://prismlibrary.com/docs/xamarin-forms/dependency-injection/platform-specific-services.html
https://github.com/PrismLibrary/Prism-Samples-Forms/tree/master/03-PlatformSpecificServices
I'm trying to create a library such as retro-lambda that reads the code at edit time or compile time and provides hints for the developer.
Let's say I'm using retro-lambda library and I created an interface that has only one method:
public interface Callback{
void onResult(boolean isSuccess, Object result);
}
When I create an instance:
Callback callback = new Callback() {
public void onResult(boolean isSuccess, Object result) {
}
}
Here the retro-lambda will create a hind for the developer to use the lambda function as following:
Callback callback = (isSuccess, result) -> {
}
What do I need to learn about how to create library that inspects the code and adds hints to the user ?
For providing an IDE hint you will want to build an Android Studio plugin.
For inspecting, modifying or generating Java source code at compile-time you will want an annotation processor.
My android app communicate with backend service through REST API . I want to mock out this API to quickly develop the front end.
I am using android volley as client side networking library.
You can use the dependency injection design pattern for this.
Basically you specify an interface that defines a set of methods corresponding to the queries you have in your REST backend, e.g.:
interface DataSupplier {
// Lookup user by ID
User getUser(int id);
// Get all blog posts posted by a specific user.
List<BlogPost> getUsersBlogPosts(int userId);
}
Now in the class where you need to query the backend, you specify an injector. This can be done in multiple ways (e.g. constructor injection, setter injection - see the wiki article for more details). An injector lets you inject an implementation of the dependency into the class that depends on it. Let us assume you use constructor injection. Your class that uses the backend would look like this:
public class DependentClass {
private final DataSupplier mSupplier;
public DependentClass(DataSupplier dataSupplier) {
mSupplier = dataSupplier;
}
// Now you simply call mSupplier whenever you need to query the mock
// (or - later in development - the real) REST service, e.g.:
public void printUserName() {
System.out.println("User name: " + mSupplier.getUser(42).getName());
}
}
Then you create a mock implementation of DataSupplier:
public class MockRestService implements DataSupplier {
#Override
public User getUser(int id) {
// Return a dummy user that matches the given ID
// with 'Alice' as the username.
return new User(id, "Alice");
}
#Override
public List<BlogPost> getUsersBlogPosts(int userId) {
List<BlogPost> result = new ArrayList<BlogPost>();
result.add(new BlogPost("Some Title", "Some body text"));
result.add(new BlogPost("Another Title", "Another body text"));
result.add(new BlogPost("A Third Title", "A third body text"));
return result;
}
}
and use that to instantiate your dependent class:
DepedentClass restClient = new DepedentClass(new MockRestService());
Now you can use restClient as if it was connected to your actual backend. It will simply return dummy objects that you can use to develop your front end.
When you are done with your front end and ready to implement your backend, you do so by creating another implementation of DataSupplier that sets up a connection to your REST backend and queries it for real objects. Let us say you name this implementation RestService. Now you can simply replace the constructor creating the MockRestService with your RestService constructor like so:
DepedentClass restClient = new DepedentClass(new RestService());
And there you have it: by swapping a single constructor call, you can change your front end code from using dummy objects to using real REST-delivered objects.
You could even have a debug flag and create the restClient according to the state of your application (debug or release):
boolean debug = true;
DependentClass restClient = null;
if (debug) {
restClient = new DepedentClass(new MockRestService());
} else {
restClient = new DepedentClass(new RestService());
}
I've recently created RESTMock. It is a library for Mocking REST API's in android tests. It can be used during development though. You would need to set it up following the README on github and create a basic Android Instrumentation test that would start your app and do nothing. This way the app is started with the Mock Server in background.
Example test:
public class SmokeTest {
#Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<MainActivity>(
SplashActivity.class,
true,
false);
#Test
public void smokeTest() throws InterruptedException {
rule.launchActivity(null);
Thread.sleep(10000000);
}
}
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
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