I don't have a lot of experience creating Java (.aar) plugins for Unity3d, but I am attempting to setup google authentication with firebase from such a plugin. To give an example of my problem, I begin by opening a unity android application, then I run the c# code below, and get a popup on my display to sign-in with google. I then choose the correct google account, then the google intent/activity disappears, then I receive no indication that "onActivityResult" has been called. No errors occur and I am unable to to do anything with the google account information that I chose.
In the image below, I click submit -> it opens the google sign-in activity in the next picture -> then it returns back to the submit screen (closing the google sign-in activity).
I think my issue is in this line:
activity.startActivityForResult(signInIntent, RC_SIGN_IN);
The "activity" in this case is a UnityPlayerActivity sent from the c# unity code below. I think this is making it so my code is looking for an "onActivityResult" method in the C# unity code rather than the java code. Any help would be greatly appreciated. Let me know if you need any other info or screenshots. Please call me out if I am being a moron.
Here is my code for calling the Google Signin Plugin From C# & Unity3d:
AndroidJNIHelper.debug = true;
using (AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
activity_context = activityClass.GetStatic<AndroidJavaObject>("currentActivity");
}
using (AndroidJavaClass pluginClass = new AndroidJavaClass("com.package.class")) {
if (pluginClass != null) {
GoogleSignInActivity = pluginClass.CallStatic<AndroidJavaObject>("instance");
GoogleSignInActivity.Call("SetContext", activity_context);
GoogleSignInActivity.Call("StartGoogleLogin", activity_context);
activity_context.Call("runOnUiThread", new AndroidJavaRunnable(() => {
GoogleSignInActivity.Call("ShowMessage", "You signed in as " + display_name);
}));
}
}
Here is the code for creating the Google SignIn Activity:
public void StartGoogleLogin(UnityPlayerActivity activity) {
gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("some url")
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(activity, gso);
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
activity.startActivityForResult(signInIntent, RC_SIGN_IN);
Log.d(TAG, "Activity Started; Waiting For Result");
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "Result Received!");
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
// Google Sign In was successful
GoogleSignInAccount account = task.getResult(ApiException.class);
someMethod(account);
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.d(TAG, "Google sign in failed", e);
}
setResult(RESULT_OK);
}
}
Thank you for your time.
Well, I solved my own problem of getting Google Authentication to work between the Android .aar plugin and Unity c#. Been working tirelessly and found some kickbutt resources.
First and foremost, I referenced the code written by a guy named cwgtech HERE.
I also went through all of his videos.
Instead of using UnitySendMessage, I was able to use a callback method similar to what CWGTech does to send a googleIdToken back to Unity and sign-in with Google into Firebase. I was also correct in thinking that my mistake was with the statement below:
activity.startActivityForResult(signInIntent, RC_SIGN_IN);
Instead of doing this, I followed CWGTech's advice and removed "activity." portion. I ran the startActivityForResult in a ResultCallback class that extends Activity. If you are still confused, dm me or comment on this post. Thanks!
Here is some of the code I used to send a callback string to Unity via a Java Proxy in written in C#. Information about writing a Java proxy can be found in the cwgtech information above. Writing the java proxy is extremely important if you want to get information to flow from Android activities to Unity C#. CWGTech explains the intricacies of java proxies way better than I could do justice.
public static final String LOGTAG = GoogleSignInActivity.TAG + "_OnResult";
public static GoogleSignInActivity.ShareStringCallback shareStringCallback;
private static final int RC_SIGN_IN = 9001;
private GoogleSignInClient mGoogleSignInClient;
private GoogleSignInOptions gso;
private CallbackManager mCallbackManager;
public void myFinish(String myresult) {
if (shareStringCallback != null) {
shareStringCallback.onLoginComplete(myresult);
}
shareStringCallback = null;
finish();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(LOGTAG, "onCreateBundle");
Intent intent = getIntent();
setContentView(R.layout.login_activity);
findViewById(R.id.buttonFacebookLogin).setOnClickListener(this);
findViewById(R.id.signInButton).setOnClickListener(this);
findViewById(R.id.buttonAnonymousSignIn).setOnClickListener(this);
}
/* GOOGLE SIGN-IN CODE */
public Intent StartGoogleLogin() {
/*
Google Sign In Client Init Code Goes Here
*/
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
return signInIntent;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//Detects some type of result from an activity, in this case Google
String id_result = "Send This To Unity";
myFinish(id_result);
}
Here is a bit more code from a different java class file. The 'Login' method is called from Unity c#.
/* INTERFACES FOR CALLBACK FUNCTIONAILITY */
public interface ShareStringCallback {
public void onLoginComplete(String result);
}
public void Login(final ShareStringCallback callback)
{
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
Log.i(TAG,"Starting Authentication");
try {
try {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setClass(mainActivity,OnResultCallback.class);
OnResultCallback.shareStringCallback = callback;
mainActivity.startActivity(shareIntent);
}
catch (Exception e)
{
e.printStackTrace();
Log.i(TAG,"error sharing intent: " + e);
}
}
catch (Exception e)
{
e.printStackTrace();
Log.i(TAG,"Error getting Uri: " + e);
}
}
catch (Exception e)
{
e.printStackTrace();
Log.i(TAG,"Error writing file: " + e);
}
}
});
}
When you start a activity from UnityPlayerActivity, the onActivityResult will be called when finished, but will have its default return value. What you can do is create a new Activity in Android, and extends UnityPlayerActivity.
In Android, create a new Activity
import com.unity3d.player.UnityPlayer;
public class OverrideUnityPlayerActivity extends UnityPlayerActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public Activity getCurrentActivity(){
return mUnityPlayer.currentActivity;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
switch (resultCode) {
case Activity.RESULT_OK:
//do something
break;
case Activity.RESULT_CANCELED:
//do something
break;
}
}
}
}
You need to set this override activity as launch endpoint in AndroidManifest.XML
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="false"
tools:replace="android:allowBackup">
<activity
android:name="com.example.unitylibrary.manager.OverrideUnityPlayerActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="app_name" android:value="app_value"/>
</activity>
</application>
</manifest>
3.Then in Unity, you can get this activity and context, also get the onActivityResult
AndroidJavaObject overridePlayerActivity;
AndroidJavaObject overrideActivity;
public void init(){
overridePlayerActivity = new AndroidJavaObject("com.example.unitylibrary.manager.OverrideUnityPlayerActivity");
overrideActivity= overridePlayerActivity.Call<AndroidJavaObject>("getCurrentActivity");
}
public void startAct(){
anonymousFunction.Call("StartActForRes", overrideActivity);
}
Hope this will solve your problem.
Related
I am trying to play a MediaPlayer from a activity, which was OPENED BY A BROADCAST RECEIVER. This works fine, if I play an internal file from the R.raw folder. But if I try to access a Mp3 file via a URI, it doesn't work anymore.
public class AlarmScreen extends AppCompatActivity {
MediaPlayer mediaPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_screen);
mediaPlayer = new MediaPlayer();
startMusic();
}
private void startMusic() {
String stringUri = element.getUri();
if (!(stringUri.equals(""))){
Uri uri = Uri.parse(stringUri);
mediaPlayer = MediaPlayer.create(this, uri);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mediaPlayer.start();
}
}, 1000);
}
}
The Error I get looks like this:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.start()' on a null object reference
I also tried to make the Media Player the following way, but it led to the same result:
Uri uri = Uri.parse(stringUri);
try {
mediaPlayer.setDataSource(this, uri);
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.prepareAsync();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mediaPlayer.start();
}
}, 300);
I guess that the problem lies somewhere within the permissions, because as far as I know the BroadCastReceivers don't have the same permissions as the normal apps.
If you need more code, please let me know.
EDIT:
I have narrowed down the problem by making the following test-project:
Here 2 Uris are created. For Uri1, I use the data from the chooser. For Uri2 I use the Uri-String from a previous round. Then these Uris are played in the start(). If I play Uri1, it works always. But if I play Uri2, it only works if Uri1 is equal to Uri2. This is only the case if the same music-file is chosen in the chooser again, as in the round where I originally copied Uri2.
I really don't understand what I'm doing wrong. Is there another way, to access music-files from your device?
private void play(){
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(this, uri2);
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.prepareAsync();
mediaPlayer.start();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uri2 = Uri.parse("content://com.android.providers.media.documents/document/audio%3A17207");
uri1 = data.getData();
String str = uri.toString();
}
private void start(){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("audio/*");
startActivityForResult(Intent.createChooser(intent, "choose:"), 1);
}
I think your problem is because of permissions.
Try to add the READ_EXTERNAL_STORAGE to your manifest.
Something like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.snazzyapp">
...
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
...
<application ...>
...
</application>
</manifest>
I'm trying to make the Play Game Services work, and for now, I'm trying a simple login attempt.
And for full two days, I'm stuck in the authentication stage.
I've followed the documentation and tried to link my app from scratch again.
double-checked my SHA-1 keys both the debug and the release. (there are two linked app in the Play Console). also checked that in the API Console everything is the same.
When I check the result from the sign-in attempt I see:
statusCode=SIGN_IN_REQUIRED.
Things that I checked or did:
SHA-1 keys
App Id correct and in the manifest
Correct Package
google-services.json downloaded
Link the app
Create a new app in the play console and new links
Firebase & Crashlytics is working
Enabled testing users
From the APK:
From API console:
Play Console:
Silent Login:
private void signInSilently() {
GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context);
if (GoogleSignIn.hasPermissions(account, signInOptions.getScopeArray())){
GoogleSignInAccount signedInAccount = account;
Log.d("TEST_SILENT", "onComplete: " + signedInAccount);
} else {
final GoogleSignInClient signInClient = GoogleSignIn.getClient(context, signInOptions);
signInClient
.silentSignIn()
.addOnCompleteListener(
activity,
new OnCompleteListener<GoogleSignInAccount>() {
#Override
public void onComplete(#NonNull Task<GoogleSignInAccount> task) {
if (task.isSuccessful()) {
GoogleSignInAccount signedInAccount = task.getResult();
Log.d("TEST_SILENT", "onComplete: " + signedInAccount);
} else {
Intent i = signInClient.getSignInIntent();
activity.startActivityForResult(i, 9001);
}
}
});
}
}
Interactive Login:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 9001) {
GoogleSignInResult res = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (res.isSuccess()) {
Log.d("ASD", "onActivityResult: " + res.getSignInAccount());
} else {
Log.e("Asd", "onActivityResult: " + res.getStatus());
}
}
}
Added the APP ID
<meta-data android:name="com.google.android.gms.games.APP_ID"
android:value="#string/app_id" />
No matter what I do, I just can't get it to sign in.
And the status from the logcat is:
E/Asd: onActivityResult: Status{statusCode=SIGN_IN_REQUIRED, resolution=null}
I am trying to run a simple multiplication with a remote service. I have AIDL server file declaring and defining methods. In AIDL, i have copied the same AIDL file as server under the server's package name.
I have given the action for the intent filter of server's service.
Still my AIDL client code is not connecting to the service.
AIDLServer:
Manifest
<service
android:name=".CalService"
android:enabled="true"
android:exported="true"
android:process=":remote">
<intent-filter>
<action android:name="mutliply"/>
</intent-filter>
</service>
ICalService.aidl
interface ICalService {
String getMessage(String name);
int getResult(int val1, int val2);
}
CalService.java
public class CalService extends Service {
public CalService() {
}
private final ICalService.Stub binder = new ICalService.Stub() {
#Override
public String getMessage(String name) throws RemoteException {
return "Hello " + name + ". The result is: ";
}
#Override
public int getResult(int val1, int val2) throws RemoteException {
return val1 * val2;
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
}
AIDLCLient:
MainActivity.java
#Override
protected void onStart() {
super.onStart();
editName = (EditText) findViewById(R.id.editName);
editVal1 = (EditText) findViewById(R.id.editVal1);
editVal2 = (EditText) findViewById(R.id.editVal2);
resultView = (TextView) findViewById(R.id.resultView);
if(calService == null) {
Log.v("CALSERVICE", "cal service null");
Intent it = new Intent("multiply");
it.setPackage("com.example.aidlserver");
if(getBaseContext().getApplicationContext().bindService(
it, connection, Context.BIND_AUTO_CREATE
) == true){
Log.v("Bind", "Bind service Succeeded");
} else {
Log.v("Bind", "Bind service failed");
}
} else {
Log.v("Cal", "Cal Service not null");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
public void mutiply(View v) {
switch (v.getId()) {
case R.id.btnCal:
int num1 = Integer.parseInt(editVal1.getText().toString());
int num2 = Integer.parseInt(editVal2.getText().toString());
try {
int result = calService.getResult(num1, num2);
String msg = calService.getMessage(editName.getText().toString());
resultView.setText(msg + result);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("onServiceConnected", "Connected");
calService = ICalService.Stub.asInterface(service);
Toast.makeText(getApplicationContext(), "Service Connected",
Toast.LENGTH_SHORT).show();
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d("onServiceDisconnected", "Disconnected");
calService = null;
Toast.makeText(getApplicationContext(), "Service Disconnected",
Toast.LENGTH_SHORT).show();
}
};
The code shows its an implicit intent used while bindService call.
Intent it = new Intent("multiply");
it.setPackage("com.example.aidlserver");
If you are above API level 21, you must update your code with an explicit intent. Please update your code with setClassName() API to make the bind service call with an explicit intent.
Intent it = new Intent("multiply");
it.setClassName("com.example.aidlserver","com.example.aidlserver.CalService");
if(getBaseContext().getApplicationContext().bindService(it, connection, Context.BIND_AUTO_CREATE) == true){
Log.v("Bind", "Bind service Succeeded");
} else {
Log.v("Bind", "Bind service failed");
}
Please note the following:
Caution: To ensure that your app is secure, always use an explicit
intent when starting a Service and don't declare intent filters for
your services. Using an implicit intent to start a service is a
security hazard because you cannot be certain of the service that
responds to the intent, and the user cannot see which service starts.
Beginning with Android 5.0 (API level 21), the system throws an
exception if you call bindService() with an implicit intent.
Ref: https://developer.android.com/guide/components/services
Also check this too,
"To receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter"
<category android:name="android.intent.category.DEFAULT"/>
https://developer.android.com/guide/components/intents-filters#Receiving
All you need is to add in client app Manifest, where you want tu bind 3rd party app Service. With the same package name you set in the Intent:
val intent = Intent("example_action")
intent.`package` = "your package name"
bindService(intent, connection, Context.BIND_AUTO_CREATE)
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.asvid.services.client">
<queries>
<package android:name="io.github.asvid.services.server" />
</queries>
...
</manifest>
Alternatively you can stay with compileSdk 29 but I don’t recommend that :)
I have an Android app that writes .txt files to the downloads folder based off your inputs, a listview that displays all your downloads and lets you click to view them (I have this working), and I'm now trying to code a way to upload them to Google Drive. I have done the developer's verification process with the SHA1 key so it should be fine as far as that goes. I often see this demo app that takes pictures and uploads them being recommended and it looks like a good code to start with and modify, but when I run it on my phone, it doesn't work-it just repeatedly asks me to select my account endlessly. The java code inside the project itself is this (I'm pretty new and don't quite understand how all of it works, but this is for the google demo in the link):
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener {
private static final String TAG = "drive-quickstart";
private static final int REQUEST_CODE_CAPTURE_IMAGE = 1;
private static final int REQUEST_CODE_CREATOR = 2;
private static final int REQUEST_CODE_RESOLUTION = 3;
private GoogleApiClient mGoogleApiClient;
private Bitmap mBitmapToSave;
/**
* Create a new file and save it to Drive.
*/
private void saveFileToDrive() {
// Start by creating a new contents, and setting a callback.
Log.i(TAG, "Creating new contents.");
final Bitmap image = mBitmapToSave;
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(new ResultCallback<DriveContentsResult>() {
#Override
public void onResult(DriveContentsResult result) {
// If the operation was not successful, we cannot do anything
// and must
// fail.
if (!result.getStatus().isSuccess()) {
Log.i(TAG, "Failed to create new contents.");
return;
}
// Otherwise, we can write our data to the new contents.
Log.i(TAG, "New contents created.");
// Get an output stream for the contents.
OutputStream outputStream = result.getDriveContents().getOutputStream();
// Write the bitmap data from it.
ByteArrayOutputStream bitmapStream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, bitmapStream);
try {
outputStream.write(bitmapStream.toByteArray());
} catch (IOException e1) {
Log.i(TAG, "Unable to write file contents.");
}
// Create the initial metadata - MIME type and title.
// Note that the user will be able to change the title later.
MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
.setMimeType("image/jpeg").setTitle("Android Photo.png").build();
// Create an intent for the file chooser, and start it.
IntentSender intentSender = Drive.DriveApi
.newCreateFileActivityBuilder()
.setInitialMetadata(metadataChangeSet)
.setInitialDriveContents(result.getDriveContents())
.build(mGoogleApiClient);
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
} catch (SendIntentException e) {
Log.i(TAG, "Failed to launch file chooser.");
}
}
});
}
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_CODE_CAPTURE_IMAGE:
// Called after a photo has been taken.
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
mBitmapToSave = (Bitmap) data.getExtras().get("data");
}
break;
case REQUEST_CODE_CREATOR:
// Called after a file is saved to Drive.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Image successfully saved.");
mBitmapToSave = null;
// Just start the camera again for another photo.
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
REQUEST_CODE_CAPTURE_IMAGE);
}
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
if (!result.hasResolution()) {
// show the localized error dialog.
GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization
// dialog is displayed to the user.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
if (mBitmapToSave == null) {
// This activity has no UI of its own. Just start the camera.
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
REQUEST_CODE_CAPTURE_IMAGE);
return;
}
saveFileToDrive();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
}
And in the manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.gms.drive.sample.quickstart"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.google.android.gms.drive.sample.quickstart.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
And with that, my main two questions are:
Any idea why the quick start project from Google is behaving the way it is?
If it's not too much, but what parts of the java code do I need to modify to make it upload a .txt file after pressing a button?
You are supposed to create a project in Google Api COnsole,then enable Drive API. Then create required credentials(SHA-1, key, CLIENT-ID) for the the android app to connect with drive api.
After getting all the credentials, include them in Manifest file and String File.
Follow the instructions here, QuickStart Android Instructions
I have a problem with my app. It is using nfc tags for some actions (opening/locking door).
The app has a intent-filter at the default activity:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/de.juwei.myapplication" />
</intent-filter>
But it seems it is ignoring the mimeType setting complety because it is starting even if i attach an empty tag to the phone and also if i try to beam data from another phone.
The code simply doing this:
public class MainActivity extends ActionBarActivity {
private NfcAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = NfcAdapter.getDefaultAdapter(this);
Intent intent = getIntent();
// see if app was started from a tag
if (mAdapter != null && intent.getType() != null && intent.getType().equals("application/de.juwei.myapplication")) {
}
}
#Override
protected void onResume() {
super.onResume();
if (mAdapter != null) {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
mAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
}
}
#Override
protected void onPause() {
super.onPause();
if (mAdapter != null) {
mAdapter.disableForegroundDispatch(this);
}
}
#Override
public void onNewIntent(Intent intent) {
if (mAdapter != null && intent.getType() != null && intent.getType().equals("application/de.juwei.myapplication")) {
// ... reading tag
}
}
}
getIntent() is null if the tag doesn't has my mimetype. So the app is just starting if for example holding to smartphones together trying to beam some data. The activity is also starting if i hold my sony smartwatch 3 to my phone...
The very strange thing is - if i try to reproduce this on a new app with just that simple code, the app is not starting on every nfc command.
But in my main app, there are no more nfc specific methods.
I am completly lost.
Does anyone know how to track/debug why the app is opening by every piece of nfc data?
Best regards,
Juergen
In enableForegroundDispatch method you have to add filters and techLists
For instance:
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
}
catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[] {
ndef,
};
mTechLists = new String[][] { new String[] { NfcF.class.getName() } };
NfcAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
mTechLists);
Looks like the problem was the enableForegroundDispatch.
I commented out both calls at onResume and onPause and changed Manifest to android:launchMode="singleTask" and it seems to work.
Must be some nfc bug, i don't know.
However, within my first tests it seems to work now, the app isn't starting every time i hold a nfc tag on back of the device.