Sunday, May 2, 2021

Common bugs when debugging/deploying Android mobile app

Android Studio does not see my device (the cell phone per se)

The error heading is "no target device found"

Possible solutions:

  • Turn on debugging mode on the phone. See also Google's manual.
    • Make "Developer options" available in the phone's Settings
    • In the Developer options, turn on "USB Debugging"
  • After connecting the phone via USB cable, see the pop up window on the phone "Default USB Configuration" (If it does not pop up, I can also find it later in USB settings of the phone). Try multiple options in this pop up: "Charging", "Storage", "MIDI", "PTP" etc. For different phones these options might be different. E. g. for now on my Motorola "PTP" works. Surprisingly, at my LG it was "Photo transfer".
  • Restart the phone
  • Change USB cable.
  • Change USB port.
  • Change the phone.

Can't see my tag in Logcat

See second box from the left on the top of the Logcat. It is the name of the process (to the right of the debugged app name).

If the box says "No debuggable processes", try to select app to the left again, then select the process to the left again.

Switch to the other tab and then back (e. g. to "Build" and then back "Log").

After the error, don't press on a phone "close the app" immediately. Otherwise I will not see the error in the log.

Google sign in result failed with code 10

Some credits are to stackoverflow. See also the post about deleting everything and creating everything from scratch.

0_Unsorted_

Create Activity for Google sign in without Firebase..

SHA-1

SHA-1 key does not match between our key, Firebase and Google Cloud Console

SHA-1 keys should match in the following sources:
  • Google Cloud Console
  • Google Play Console -> App signing (in case of release)
  • Firebase Console
  • Local google-services.json file
  • Value from the output of ./gradlew signingReport (local machine keystore)

Value from the output of ./gradlew signingReport (local machine keystore) is different than in other sources

In 2 words, add new local SHA-1 key from gradlew report to the Firebase Console.

First, need to get local SHA-1 key by either one of the following ways:
1) Via the terminal. It does not work always though (see the second way infra then).
In the terminal, go to project folder and run:
./gradlew signingReport
The output will be something like that:







2) Via the Android Studio.
The best way is provided with this stackoverflow answer:
- In the Android Studio, open Gradle window via View -> Tool Windows -> Gradle.
- Click on "Execute Gradle Task" button (it looks like an elephant in the top left corner)
- On the new open window, press type "gradle signingreport" without quotes and press Enter.
- See the result in the Run window (View -> Tool Windows -> Run).

Once I had a problem when debugging and deploying the app from the new computer. So Android Studio changed the SHA-1 key. Now it doesn't match SHAs from Firebase Console and Google Cloud Console.

Just in case, let's recreate this local SHA:
- Remove (rm -rf) the debug.keystore.lock from the $HOME/.android/ folder.
- Create new SHA-1. Gradle in Android Studio does it automatically when rebuilding the app. So in Android Studio we need to press Build -> Clean the project, then Build -> Rebuild the project.
- Download again google-services.json file from Firebase console.

Then, run ./gradlew signingReport from the project folder again. Copy SHA-1 key from the output (consisting of 20 pairs of numbers divided by colons) and insert it into Firebase Console. To insert it in the Firebase Console:

  1. Go to https://console.firebase.google.com
  2. Select your project
  3. In the to left corner, press the "Settings" wheel button next to "Project Overview"
  4. Press "Project Settings"
  5. Scroll down to the "Your apps" section
  6. See section "SHA certificate fingerprints"
  7. Press "Add fingerprints"
  8. Insert fingerprint from the ./gradlew signingReport from supra.

Just in case, download from Firebase Console google-services.json file again to local app files.

Once we added SHA-1 key to Firebase Console, Firebase will automatically populate it to the Google Cloud Console.

SHA-1 for Production version doesn't match with Firebase and Google Cloud consoles

Probably the issue is in wrong SHA-1 key. So the idea is as follows. Once we create an app and test it via our local computer on our local device (android phone) we generate SHA-1 debugging key (just for debugging, not for release). Later at the Google Cloud console and at Firebase console SHA-1 might need to be updated after launching the app to the production. That is because new SHA-1 production key is generated upon generating the signed apk package (which in turn we use to release the app to the Google play).
Once we update SHA-1 key in the app in Firebase console, it should populate automatically to Google Cloud Console. However, just to be sure we need to verify that at Google Cloud Console the right release key is propagated.
Finally, the problem with production for me was solved as follows..
Hierarchy of dependencies in Firebase Console is as follows: In Firebase we have one project, in the project we create one app, in the app we create many SHA-1 keys: 
  1. One SHA-1 key is the very first one from debug, it was created during the first build by Android Studio.
  2. Second SHA-1 key is created by Android Studio when we launch in Android Studio "Build/Generate signed bundle/APK" for the production release.
  3. Third SHA-1 is provided in the Google Play Console after we upload the signed bundle/APK to production release. In the Google Play Console go on the left pane to Setup -> App integrity. We will see the section "Play App Signing". There are 2 subsections there: "App signing key certificate" and "Upload key certificate". "Upload key certificate" contains the SHA-1 key that was generated during launching in Android Studio "Build/Generate signed bundle/APK" for the production release.

    "App signing key certificate" contains new SHA-1 key that we need to add to Firebase Console. 

    Note that Google changes its interface very often and these items could go under new menu sections, just need to look for them or google them.
So in the Firebase Console, open the project -> Settings -> consequent app of the project. In the app, add all three SHA-1 supra that are not there yet by pressing "add fingerprint". No need to create another apps in the Firebase project. Just add all the SHA-1 keys to the same app.
Then in the Google Cloud Console, Firebase automatically creates OAuth 2.0 Client IDs for each of the SHA-1 keys. So no need to make changes in Google Cloud Console. Just check that finally if we have 3 SHA-1 keys, in the Google Cloud Console we have four OAuth 2.0 Client IDs: three for consequent SHA-1 keys and one Web App.

Then download from Firebase Console new google-services.json file to the app's code. Make a signed release again and upload in to Google Play Console again, now it should work.

SHA-1 key is from the old project

Once I deleted my project from Firebase, created a new one and used the old SHA-1 key. Google doesn't allow to do it because it takes up to 1 month for the old project to be completely dismissed from the Google services. So we cannot use old SHA-1 key at that time. Need to create a new one. Credits to this stackoverflow answer.
On Linux, the old SHA-1 key is stored there: $HOME/.android/. So we can do the following:
- Merely remove (rm -rf) the debug.keystore.lock from the .android/ folder.
- Create new SHA-1. Gradle in Android Studio does it automatically when rebuilding the app. So in Android Studio we need to press Build -> Clean the project, then Build -> Rebuild the project.
- Download again google-services.json file from Firebase console.

SHA-1 key is not populated

That is just an idea to check. Infra web_client_id has problems to be populated. SHA-1 might have the same problems in within the app?

    Web_client_id

    Value is not populated

    Another option could be failure with default_web_client_id that is used in login activity in
        val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
    That value should be automatically populated in values.xml file:
        <string name="default_web_client_id" translatable="false">CHANGE-ME</string>
    From the google-services.json file:
      "client": [
        {
          "client_info": {
            "mobilesdk_app_id": "...",
            "android_client_info": {
              "package_name": "com.exa.myproject"
            }
          },
          "oauth_client": [
            {
              "client_id": default_web_client_id value is here
    For some reason, this value might not be populated automatically. So we can hardcode it. In the strings.xml file, create default_web_client_id_hardcoded string with the value from "client_id" from google-services.json file. Then in the login activity, replace default_web_client_id with default_web_client_id_hardcoded. Credits to stackoverflow.

    Value is of string type

    Make sure also that getString(R.string.default_web_client_id) gets actual string, not the integer value. To double check it, log it in the Logcat:
          Log.i(TAG, getString(R.string.default_web_client_id_hardcoded))

    Value type is Web application

    Google asks to paste "Web Application" type id, not the "Android" type. In the Google Cloud Console, we can see 2 apps. One is automatically created by Firebase when we create Firebase app for the Firebase project. Another one is created at the step of configuring Google API Console project.

    Package name

    Names don't match

    Package name like "com.example.myproject" should match between the following:
    • Google Cloud console
    • Android package code - gradle files etc
    • Firebase console

    Package name is from the old project

    There is a known issue that SHA-1 key cannot be taken from the old project. So probably the same problem might occur here. So we need to change package name everywhere (local store, Firebase Console, Google Cloud Console). This solution has not been verified yet.

    Proper project is selected

    At Google Cloud Console, make sure that all the steps are for the proper project which is listed at the top of the web page in the drop down menu.

    google-services.json file is not uploaded

    After implementing any of the steps supra, we need to download google-services.json file again from the Firebase Console.

    Could not set unknown property 'fragment_version' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler

    The problem comes from the app level build.gradle file. See in the log the reference to the certain line of the file. It could be caused by using improper syntax of improper language. E. g. we declare variable with Kotlin keyword "var" instead of Groovy "def" that is needed for this particular build.gradle file.

    Unresolved reference: findViewById

    That might be because we are calling findViewById from the fragment, not from the activity. So in the Fragment, we can use function of getView().findViewById(R.id.foo). All credits are to stackoverflow.
    Also in the fragment's onCreateView function, we can call
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            val view = inflater.inflate(R.layout.my_fragment, container, false)
            val signInButton: SignInButton? = view?.findViewById(R.id.my_button)
            return view
        }

    Firebase error: "Error updating Google"

    This comes as a pop up message when I am trying to add Google sign in account in the Authentication options of Firebase Console for my project. 
    When Google sign in method is not enabled in Firebase, attempting to sign in via the app gives the following error in the app's log:
     signInWithCredential:failure com.google.firebase.auth.FirebaseAuthException: The given sign-in provider is disabled for this Firebase project. Enable it in the Firebase console, under the sign-in method tab of the Auth section. [ The identity provider configuration is not found. ]
    This error is rare and it seems like it is on the side of Firebase team, not us. Thus, the best bet is to contact Firebase support. 

    Solutions from customer service (usually not working)

    Some of the preliminary advises from support and stackoverflow include:
    - Try to do the same from incognito mode, different browser, different device. Though Firebase customer service advice this to everybody who having such a problem, I know nobody for whom it worked :(
    - Try to implement sign in with Google API Console without Firebase. In case of success, we will be 100 percent sure that the error is on the Firebase side.

    Nuclear solution

    Documented here also.
    For me personally worked nuclear solution: recreate the Firebase and Google Cloud projects. The solution is costly if the Firebase project already has database. After deleting everything, first create a Firebase project. Than the Google Cloud project will be created automatically - no need to create a separate Google Cloud project.
    After this nuclear explosion, don't forget to delete and create new SHA-1 and web_client_id keys:
    - delete the debug.keystore
    - run ./gradlew signingreport from the app's directory to make sure there are no keys remaining
    - build the app in Android Studio - it will generate new keys automatically during new build
    - run ./gradlew signingreport from the app's directory to make sure that new keys are there
    The lesson for the future for me and others: loose coupling is a must when dealing with Google and Firebase. At any moment of time, we should be ready to easily switch from Firebase to adequate database. We should even be ready to switch from Google to other platform.

    Unresolved reference: FirebaseMessaging

    In my case, this error came while implementing FCM (Firebase Cloud Messaging) for the purpose of notifications on user's Android device. I am just following the official Google and Firebase guide, that directs to retrieve the token with the following Kotlin code:
    FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
    Log.w(TAG, "Fetching FCM registration token failed", task.exception)
    return@OnCompleteListener
    }

    // Get new FCM registration token
    val token = task.result

    // Log and toast
    val msg = getString(R.string.msg_token_fmt, token)
    Log.d(TAG, msg)
    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
    })
    Interestingly enough, their own project sample reference Firebase libraries in other way:
    Firebase.messaging.getToken().addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
    Log.w(TAG, "Fetching FCM registration token failed", task.exception)
    return@OnCompleteListener
    }

    // Get new FCM registration token
    val token = task.result

    // Log and toast
    val msg = getString(R.string.msg_token_fmt, token)
    Log.d(TAG, msg)
    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
    })
    So if our code is written with Kotlin not with Java, we can use the working template from the sample supra. I. e. we call Firebase.messaging.getToken() instead of FirebaseMessaging.getInstance().token.
    Finally, Android Studio suggested me to replace property access and for now in Kotlin the following code works fine:
    Firebase.messaging.token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
    Log.w(TAG, "Fetching FCM registration token failed", task.exception)
    return@OnCompleteListener
    }
    val token = task.result
    })

    Failed to authenticate, have you run firebase login?

    Question:

    I am following instructions for Firebase functions. I have successfuly login from my console, however when I am trying to deploy functions, terminal gives an error: enter image description here

    oleg@oleg-HP-EliteBook-8460p:~/Desktop/Oleg/projects/firebase-functions$ firebase login

    Already logged in as [my user email]

    oleg@oleg-HP-EliteBook-8460p:~/Desktop/Oleg/projects/firebase-functions$ sudo firebase deploy --only functions

    Error: Failed to authenticate, have you run firebase login? (node:11224) MetadataLookupWarning: received unexpected error = Unsuccessful response status code. Request failed with status code 403 code = 403 Having trouble? Try firebase [command] --help

    So the error is kind of controversial. Firstly, Firebase says that I am already successfully logged in. Right next, Firebase says that I am not logged in... I suspect there should be some setting for user name or something like that in kind of local firebase.json file or other files, but I didn't find it.. Or should I change something in the Firebase Console?

    Answer:

    The difference is that you're running firebase login and then sudo firebase deploy. You should never need to use sudo with Firebase.
    Source:

    Gradle sync failed: Sync failed: reason unknown

    In the top part of the window, press Android Studio Menu -> Rebuild Project.
    Then in the bottom part of the window press "Build" tab.
    In the logging part of the tab, it can show more information and suggestions to fix the problem.

    Because an app is obscuring permission request setting cannot verify your response

    Probably, simultaneously with debugging some other app is running on the phone. That app could be in front of other apps, such as YouTube picture-in-picture option etc. Just close it for the time of debug.

    No comments:

    Post a Comment