How to communicate with Google My Business API with Kotlin Application (Android Studio)?


For weeks now i have been trying to get this to work, with no success so far. I want to create an application with which i can create a new Event on my Google Business (for Google Search, Google Maps, etc.). Afaik, for this Google has the Google Business Profile API. In this Documentation, there also even exists the Page “Create Posts on Google”. However, none of their documentation makes my dumbass here understand, what i need to do to be able to use that API in my code.

I have tried several approaches:
Google has a library for google my business – place actions, for Java. I remember that I tried to integrate it into my Code, but with no success, since i cant find any proper documentation or anything on it.
Also, i tried just using plain old HTTP requests, but now I am stuck here as well.

So far, i have managed to get an access token through their Google Sign In library, but using that to request the creation of a new Event only results in the 401 (Unauthorized) Error.

This is my current code:

AutoPublisher.kt:

package <package_name>

import AutoPublisher_GMB_Helper
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.Scope
import com.google.android.gms.tasks.Task

class AutoPublisher : Fragment() {

    private lateinit var accessToken: String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestScopes(Scope("https://www.googleapis.com/auth/business.manage"))
            .requestEmail()
            .requestIdToken(getString(R.string.googleWebClientID))
            .build()

        val signInLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                Log.e("AAAAAA", result.toString())
                if (result.resultCode == RESULT_OK) {
                    val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
                    handleSignInResult(task)
                } else {
                    Log.e("AWWWWWWW", "Not successful, Sign in failed")
                }
            }

        val googleSignInClient = GoogleSignIn.getClient(this.requireActivity(), signInOptions)
        val signInIntent = googleSignInClient.signInIntent

        signInLauncher.launch(signInIntent)
    }

    private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
        try {
            // Signed in successfully, get the access token
            val account = completedTask.getResult(ApiException::class.java)
            accessToken = account?.idToken!!
            println(accessToken)

        } catch (e: ApiException) {
            Log.e("WAAAAAAAAAAAA", "Not successful, Sign in failed: \n\n" + e.printStackTrace())
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_autopublisher, container, false)

        //
        // Publishing
        //
        view.findViewById<Button>(R.id.googleMyBusiness_btn).setOnClickListener {
            val helper = AutoPublisher_GMB_Helper(accessToken, getString(R.string.googleAccountID))
            helper.createPost(getString(R.string.googleLocationID), "TestEvent", "Thisisatestevent", "https://raw.githubusercontent.com/test-images/png/main/202105/cs-black-000.png")
        }



        return view
    }
}

AutoPublisher_GMB_Helper.kt:

import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException

class AutoPublisher_GMB_Helper(private val accessToken: String, private val accountID: String) {

    private val client = OkHttpClient()

    @Throws(IOException::class)
    fun createPost(locationId: String, title: String, description: String, sourceUrl: String, languageCode: String = "de-DE") {
        val url = "https://mybusiness.googleapis.com/v4/accounts/${accountID}/locations/$locationId/localPosts"


        // TODO Add date / time selection
        val json = """
            {
                "languageCode": "$languageCode",
                "summary": "$description",
                "event": {
                    "title": "$title",
                    "schedule": {
                        "startDate": {
                            "year": 2024,
                            "month": 4,
                            "day": 2,
                        },
                        "startTime": {
                              "hours": 9,
                              "minutes": 0,
                              "seconds": 0,
                              "nanos": 0,
                        },
                        "endDate": {
                            "year": 2024,
                            "month": 4,
                            "day": 2,
                        },
                        "endTime": {
                              "hours": 17,
                              "minutes": 0,
                              "seconds": 0,
                              "nanos": 0,
                        }
                    }
                },
                "callToAction": {
                    "actionType": "LEARN_MORE",
                    "url": "https://example.com",
                },
                "media": [
                    {
                        "mediaFormat": "PHOTO",
                        "sourceUrl": "$sourceUrl",
                    }
                ],
                "topicType": "EVENT",
                "validateOnly": "True"
            }
        """.trimIndent()

        val requestBody = json.toRequestBody("application/json".toMediaTypeOrNull())
        val request = Request.Builder()
            .url(url)
            .post(requestBody)
            .addHeader("Authorization", "Bearer $accessToken")
            .addHeader("Content-Type", "application/json")
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                println("Failed to create post: ${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                if (!response.isSuccessful) {
                    println("Failed to create post: ${response.code} - ${response.message}")
                } else {
                    println("Post created successfully.")
                }
            }
        })
    }
}

Any further help, hints or ideas would be hugely appreciated – thank you!

Edit: I have a suspicion that the requested scope is not correct, hence why it returns RESULT_CANCELED when trying to authenticate. When opening the scope URL, i am only greeted with an error and a not very helpful link.



Source link

Leave a Comment