IBM Watson UnAuthorized - android

I implemented IBM watson Assistant and it works perfectly fine on android debug. Problem comes when I build a signed apk. It always says Unauthorized. I don't think its the key because its working fine on debug mode. I need some help because the project is live.
What I have tried so far is to change the key in IBM cloud and tried other keys but it raises not found exception of which i think is caused by wrong key. Im I supposed to allow something in IBM cloud for signed apk? or is there a certificate from signed apk that I have to upload in IBM cloud?
Im using IBM watson Assistant v2
private Assistant watsonAssistant;
private Response<SessionResponse> watsonAssistantSession;
private void createServices() {
watsonAssistant = new Assistant("2020-04-01", new IamAuthenticator(getString(R.string.assistant_apikey)));
watsonAssistant.setServiceUrl(getString(R.string.assistant_url));
}
private void sendMessage(){
Thread thread = new Thread(() -> {
try {
if (watsonAssistantSession == null) {
ServiceCall<SessionResponse> call = watsonAssistant.createSession(new CreateSessionOptions.Builder().assistantId(getString(R.string.normal_assistant_id)).build());
watsonAssistantSession = call.execute();
}
MessageInput input = new MessageInput.Builder()
.text(userInput)
.build();
MessageOptions options = new MessageOptions.Builder()
.assistantId(getString(R.string.normal_assistant_id))
.input(input)
.sessionId(watsonAssistantSession.getResult().getSessionId())
.build();
Response<MessageResponse> response = watsonAssistant.message(options).execute();
if (response.getResult().getOutput() != null && !response.getResult().getOutput().getGeneric().isEmpty()) {
List<RuntimeResponseGeneric> responses = response.getResult().getOutput().getGeneric();
for (RuntimeResponseGeneric r : responses) {
switch (r.responseType()) {
case "text":
aiResponse = r.text();
aiConversationList.add(new AIConversation(r.text(), "ai", System.currentTimeMillis()));
break;
default:
Log.e("Error", "Unhandled message type");
}
}
runOnUiThread(() -> {
sendConvoToServer(userInput, aiResponse);
txtWelcomeAI.setVisibility(View.VISIBLE);
aiAdapter.notifyItemInserted(aiConversationList.size() - 1);
userInputTxt.setEnabled(true);
pRecyclerView.scrollToPosition(aiConversationList.size() - 1);
aStatus.setText("online");
});
}
} catch (Exception e) {
e.printStackTrace();
Log.e("IBM_EXCEPTION", e.toString());
aiConversationList.add(new AIConversation("Oops! Something went wrong", "ai", System.currentTimeMillis()));
aiAdapter.notifyItemInserted(aiConversationList.size() - 1);
runOnUiThread(() -> {
pRecyclerView.scrollToPosition(aiConversationList.size() - 1);
aStatus.setText("online");
userInputTxt.setEnabled(true);
});
}
});
thread.start();
}

In case anyone else will have a problem between debug and release apks like the one I had, try to check if you have done obfuscation. If so, then obfuscation is probably a problem. At least it was for me. So, either disable obfuscation from your build.gradle on app level or add some rules in proguard-rules

Related

Android: Receiving wrong UTM from Google Ads

According to my boss, some of our applications have been invested on advertising of the app via Google Ads. In order for them to parse the data and analyze them correctly, they are using the UTM auto-tagging approach. It is my job from the client (Android Device) to send the UTM using Firebase Analytics and also a custom event to Firebase depending on this UTM.
However, our data shows that both Firebase SDK and our events are transferred incorrectly. The click numbers and the download numbers do not match. Since both of them are incorrect, I'm guessing the received UTM on the device itself is wrong, and this needs to be received correctly and I am unable to find an answer for this.
I'm using Install Referrer Library to track down what the UTM is after the app is downloaded to the device. I am guessing Firebase SDK also uses somewhat similar approach. On our end, the UTM is recorded to SharedPreferences and it is not queried again if the query was successful.
Here is the related code for it (the processReferrer method basically parses the UTM according to our needs):
/**
* Checks if the referrer information is recorded before, if not, creates
* a connection to Google Play and saves the data to shared preferences.
*/
private static void fetchReferrerInformation(Context context)
{
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
String utmData = preferences.getString(UTM_DATA, "");
// Only connect if utm is not recorded before.
if (TextUtils.isEmpty(utmData))
{
InstallReferrerClient client;
try
{
client = InstallReferrerClient.newBuilder(context).build();
client.startConnection(new InstallReferrerStateListener()
{
#Override
public void onInstallReferrerSetupFinished(int responseCode)
{
switch (responseCode)
{
case InstallReferrerClient.InstallReferrerResponse.OK:
{
ReferrerDetails response;
try
{
response = client.getInstallReferrer();
}
catch (Exception e)
{
Log.e(TAG, "Error while fetching referrer information.", e);
if (Fabric.isInitialized())
Crashlytics.logException(new IllegalStateException("Exception while fetching UTM information.", e));
return;
}
if (response != null)
{
processReferrer(context, response.getInstallReferrer());
}
break;
}
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
{
Log.w(TAG, "Install referrer client: Feature is not supported.");
break;
}
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
{
Log.w(TAG, "Install referrer client: Service is unavailable.");
break;
}
}
try
{
client.endConnection();
}
catch (Exception ignored){}
}
#Override
public void onInstallReferrerServiceDisconnected()
{
// Do nothing, we need to fetch the information once and
// it is not really necessary to try to reconnect.
// If app is opened once more, the attempt will be made anyway.
}
});
}
catch (Exception e)
{
if (Fabric.isInitialized())
Crashlytics.logException(new IllegalStateException("Exception while fetching UTM information.", e));
}
}
else
Log.i(TAG, "UTM is already recorded, skipping connection initialization. Value: " +
utmData);
}
The approach is pretty simple, however the data seems to be wrong. So, does it seem that the implementation is somewhat incorrect? If not, why is the data received from Google Ads is wrong? Any help is appreciated, thank you very much.
Edit: Upon some testing, here is what I've found:
Works:
An API 19 real device (GM Discovery II Mini) and in between API 25-29 emulators with Play Store installed. Edit: UTM can also be fetched with API 23 and 24 Genymotion Emulators, where Play Store is installed.
Doesn't work:
An API 24 Android Studio emulator with latest Google Play Services and Play Store installed (device is also logged in to my account), and a real device (General Mobile 4G Dual, API 23) cannot query the UTM information. The code below lands on the case of InstallReferrerResponse.FEATURE_NOT_SUPPORTED. So I am almost sure that the install referrer client is bugged on some API levels.
Edit: Opened an issue to the Google: https://issuetracker.google.com/issues/149342702
As I don't know how you are processing the resonse, I can show you the way we did it in our implementation.
ReferrerDetails response = referrerClient.getInstallReferrer();
if (response == null) {
break;
}
String[] installReferrer = response.getInstallReferrer().split("&");
if (installReferrer.length >= 1) {
utmSource = installReferrer[0].split("=")[1];
}
if (installReferrer.length >= 2) {
utmMedium = installReferrer[1].split("=")[1];
}
Compare this snippet with yours and check if anything differs.

Looking up version and forcing an update in xamarin

There are many posts about doing this in java, but I found that NSoup (the port of the JSoup library) doesn't work for me, so I failed to port it to c#/Xamarin. For multiplayer functions of a game I'm working on, I need to make sure clients are synced before starting multiplayer matchmaking. This means I have to force the user to update the app if there's a new version available before they're allowed to invite other players to matches, join quick matches, etc..
So when a user presses the "quick match" button, for example, I need to:
Check for the version name (im incrementing version name, not code, for breaking changes)
Compare the version name from that to the current version name installed
3.
-If the newer version name is greater than the current one, I need to give the user the option to update their app, and send them to the google play store page for my app if they choose 'yes'. Then I'll just let them update from there and our work is done.
-If the versions are the same, allow whatever the button's functionality (i.e sending them to the waiting room for matchmaking) to proceed.
Create the methods necessary to check for updates and act accordingly:
private void CheckUpdate(Action doIfUpToDate)
{
if(NeedUpdate())
{
Android.App.AlertDialog.Builder alert = new Android.App.AlertDialog.Builder(this);
alert.SetTitle("New Update");
alert.SetMessage("You must download the newest version of this to play multiplayer. Would you like to now?");
alert.SetCancelable(false);
alert.SetPositiveButton("Yes", new EventHandler<DialogClickEventArgs>((object sender, DialogClickEventArgs e) => GetUpdate()));
alert.SetNegativeButton("No", delegate{});
alert.Show();
}
else
{
doIfUpToDate.Invoke();
}
}
private bool NeedUpdate()
{
try
{
var curVersion = PackageManager.GetPackageInfo(PackageName, 0).VersionName;
var newVersion = curVersion;
string htmlCode;
//probably better to do in a background thread
using (WebClient client = new WebClient())
{
htmlCode = client.DownloadString("https://play.google.com/store/apps/details?id=" + PackageName + "&hl=en");
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlCode);
newVersion = doc.DocumentNode.SelectNodes("//div[#itemprop='softwareVersion']")
.Select(p => p.InnerText)
.ToList()
.First()
.Trim();
return String.Compare(curVersion, newVersion) < 0;
}
catch (Exception e)
{
Log.Error(TAG, e.Message);
Toast.MakeText(this, "Trouble validating app version for multiplayer gameplay.. Check your internet connection", ToastLength.Long).Show();
return true;
}
}
private void GetUpdate()
{
try
{
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + PackageName)));
}
catch (ActivityNotFoundException e)
{
//Default to the the actual web page in case google play store app is not installed
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("https://play.google.com/store/apps/details?id=" + PackageName)));
}
}
And then from a given button that could start a multiplayer game:
var quickMatchButton = FindViewById<Button>(Resource.Id.button_quick_game);
quickMatchButton.Click += new EventHandler((object sender, EventArgs e) => CheckUpdate(() => startQuickMatch()));

How to check if firebase service is available?

In cases when the app is running behind a firewall or there is a network outage or some sort of censorship, How can we check using code to see if the app can access the firebase systems?
You should check if Google Play Service is available like this:
/**
* Check the device to make sure it has the Google Play Services APK. If it
* doesn't, display a dialog that allows users to download the APK from the
* Google Play Store or enable it in the device's system settings.
*/
public static boolean checkPlayServices(Context context) {
int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable
(context);
if (resultCode != ConnectionResult.SUCCESS) {
Log.i(TAG, "This device does not support Google Play Services. " +
"Push notifications are not supported");
return false;
}
return true;
}
You need to add the following line to your build.gradle also.
compile 'com.google.android.gms:play-services-gcm:11.8.0'
I am guessing currently there is no way you can check whether Firebase is available or not from codes inside the app. However you can check if Firebase itself is working fine by checking Firebase Status Dashboard.
In this site you can also find in what date Firebase service was not available or unstable in the past.
Hope it helps in some way.
https://status.firebase.google.com/
As the
FirebaseApp.getInstance() throws IllegalStateException
you my try below solution
private val isFirebaseEnabled: Boolean
get() {
return try {
FirebaseApp.getInstance() != null. //that is always true, nevertheless it will throw exception if Firebase is not available
} catch (e: IllegalStateException) {
false
}
}
unfortunately it won't check actual network restrictions. You may try to ping FCM and catch connection timeout. E.g.
private fun isInternetAvailable(): Boolean {
return try {
val connection = URL("https://theUrl.com").openConnection() as HttpURLConnection
connection.setRequestProperty("User-Agent", "Test")
connection.connectTimeout = 10000
connection.connect()
connection.disconnect()
true
} catch (e: Exception) {
false
}
}

Working with azure mobile service in android

I am working on a project in which I have to work with Azure Back end, I have inserted data into the table, but don't know how to get its response and where should I use Json parsing .. below is my code .. please guide me about this
mClient.getTable(TodoItem.class).insert(item, new TableOperationCallback<TodoItem>() {
public void onCompleted(TodoItem entity, Exception exception, ServiceFilterResponse response) {
if (exception == null) {
// Insert succeeded
Toast.makeText(getApplicationContext(),"yes", Toast.LENGTH_LONG).show();
} else {
// Insert failed
String msg=exception.getCause().getMessage();
Toast.makeText(getApplicationContext(), "No", Toast.LENGTH_LONG).show();
}
}
});
For information on using the Android client SDK for Azure Mobile Apps, see the following articles:
Create an Android app
Enable offline sync for your Android mobile app
How to use the Android client library for Mobile Apps

GoogleAccountCredential + Google Play Services + Refresh Token - how this works together?

I have published a pretty successful app about 2 weeks ago. But starting from yesterday, users keep sending me emails about Drive not being accessable anymore. After a quick debug, I found that requests to the Drive API now return "403 Forbidden" -> "Access Not Configured".
I think this might be an issue with the refresh token not being handled properly.
I'm using the following code (from the Android Drive SDK samples):
mCredentials = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
String accountName = PreferenceManager.getDefaultSharedPreferences(this).getString(PREF_DRIVE_NAME, null);
if (accountName != null) {
setupDrive(accountName);
} else {
startActivityForResult(mCredentials.newChooseAccountIntent(), 0);
}
setupDrive(...) looks like this:
mCredentials.setSelectedAccountName(accountName);
try {
mCredentials.getToken();
} catch (Exception e) {
Log.w(AbstractDriveActivity.class.getSimpleName(), "Error getting auth token", e);
if (e instanceof UserRecoverableAuthException) {
Intent intent = ((UserRecoverableAuthException) e).getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_FROM_BACKGROUND);
startActivity(intent);
} else {
Toast.makeText(AbstractDriveActivity.this, getString(R.string.toast_drive_setup_error),
Toast.LENGTH_SHORT).show();
finish();
}
}
drive = new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(),
mCredentials).build();
Any idea what might be wrong here?
From my understanding, GoogleAccountCredential uses the Google Play Services to manage the OAuth2 flow and all you need to provide is the username. Am I wrong? Did I miss something?
Btw: After clearing app data, selecting the Google Account again, everything works fine. That's why I think that it has something to do with the refresh token.
Goddchen
No guaranty, but the problem might come from here:
mCredentials = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
This method appears as deprecated to me. You should upgrade your SDK and environment and change it to:
mCredentials = GoogleAccountCredential.usingOAuth2(this, Arrays.asList(DriveScopes.DRIVE));

Categories

Resources