androidandroid-intent

Android Unresolved reference @MainActivity from another activity


(I'm an Android newbie.)

Goal: When a message is received from the HTML page's JavaScript, switch to a different activity.

Error: Unresolved reference @MainActivity

The file MainActivity.kt exists in the same directory with class name MainActivity. Thank you!

FILE: WebViewActivity.kt

package io.github.g00fy2.quickiesample
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat.startActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat


class WebViewActivity : AppCompatActivity() {
  public class JsObject {
    @JavascriptInterface
    public fun msg(): String {
      return "From Android!"
    }

    @JavascriptInterface
    fun postMsg(msg: String) {
                               // ERROR from this@MainActivity
      val mainActivityIntent = Intent(this@MainActivity, MainActivity::class.java)
      mainActivityIntent.putExtra("postMsg", msg);
      startActivity(mainActivityIntent)
    }
  }

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

Solution

  • Your problem is Not Android, but OOP. You are trying to access WebViewActivity object outside of it's scope, I mean JsObject class has a new scope that can access nothing from your Activity members, despite it is inside the class. You can make JsObject as inner class, but I would not recommend to do so.

    If you need a single method that has an ability to use Context related methods you can pass the method of your WebViewActivity methods as @JavascriptInterface like below:

    class WebViewActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            ...
            webView.addJavascriptInterface(this, "MessageReceiver")
        }
    
        @JavascriptInterface
        fun postMsg(msg: String) {
            val mainActivityIntent = Intent(this, MainActivity::class.java)
            mainActivityIntent.putExtra("postMsg", msg);
            startActivity(mainActivityIntent)
        }
    }
    

    And another option is to make separate class to pass into WebView, but actually calls nothing that related to a Context. Instead provide a callback to an Activity to control the call. Example:

    interface MessageReceiver {
        fun onMessageReceived(msg: String)
    }
    
    class JsObject(private val messageReceiver: MessageReceiver) {
    
        @JavascriptInterface
        fun msg(): String {
            return "From Android!"
        }
    
        @JavascriptInterface
        fun postMsg(msg: String) {
            messageReceiver.onMessageReceived(msg)
        }
    }
    
    class WebViewActivity : AppCompatActivity(), MessageReceiver {
    
        private val jsObject = JsObject(this)
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
        }
    
        override fun onMessageReceived(msg: String) {
            val mainActivityIntent = Intent(this@WebViewActivity, MainActivity::class.java)
            mainActivityIntent.putExtra("postMsg", msg);
            startActivity(mainActivityIntent)
        }
    }