Home > Net >  Embed activity inside jetpack composable
Embed activity inside jetpack composable

Time:01-13

Can we embed activity inside composable, so for example, when navigate to that composable its shows the activity content inside it(and not just start activity outside the composable), That what i succeed so far, but its just show the activity and not embed it

@Composable
fun MyContent() {
  val context = LocalContext.current
  val intent = Intent(context, MyActivity::class.java)
  context.startActivity(intent)
}

The activity

class WebViews : ComponentActivity() {


  var webView: WebView? = null
  private var mUploadMessage: ValueCallback<Uri>? = null
  var uploadMessage: ValueCallback<Array<Uri>>? = null
  val REQUEST_SELECT_FILE = 100
  private val FILECHOOSER_RESULTCODE = 1

  var url = "http://example.com"


  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_web_views)
    webView = findViewById<View>(R.id.webView) as WebView
    webView!!.settings.javaScriptEnabled = true
    webView!!.loadUrl(url)
    webView!!.webViewClient = xWebViewClient()
    webView!!.webChromeClient = object : WebChromeClient() {
      // For 3.0  Devices (Start)
      // onActivityResult attached before constructor
      protected fun openFileChooser(
        uploadMsg: ValueCallback<Uri>?, acceptType: String?
      ) {
        mUploadMessage = uploadMsg
        val i = Intent(Intent.ACTION_GET_CONTENT)
        i.addCategory(Intent.CATEGORY_OPENABLE)
        i.type = "image/*"
        startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE)
      }

      // For Lollipop 5.0  Devices
      override fun onShowFileChooser(
        mWebView: WebView?,
        filePathCallback: ValueCallback<Array<Uri>>?,
        fileChooserParams: WebChromeClient.FileChooserParams
      ): Boolean {
        if (uploadMessage != null) {
          uploadMessage!!.onReceiveValue(null)
          uploadMessage = null
        }
        uploadMessage = filePathCallback
        var intent: Intent? = null
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          intent = fileChooserParams.createIntent()
        }
        try {
          startActivityForResult(intent, REQUEST_SELECT_FILE)
        } catch (e: ActivityNotFoundException) {
          uploadMessage = null
          return false
        }
        return true
      }

      //For Android 4.1 only
      protected fun openFileChooser(
        uploadMsg: ValueCallback<Uri>?,
        acceptType: String?,
        capture: String?
      ) {
        mUploadMessage = uploadMsg
        val intent = Intent(Intent.ACTION_GET_CONTENT)
        intent.addCategory(Intent.CATEGORY_OPENABLE)
        intent.type = "image/*"
        startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE)
      }

      protected fun openFileChooser(uploadMsg: ValueCallback<Uri>?) {
        mUploadMessage = uploadMsg
        val i = Intent(Intent.ACTION_GET_CONTENT)
        i.addCategory(Intent.CATEGORY_OPENABLE)
        i.type = "image/*"
        startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE)
      }
    }
  }

  override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
    super.onActivityResult(requestCode, resultCode, intent)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      if (requestCode == REQUEST_SELECT_FILE) {
        if (uploadMessage == null) return
        uploadMessage!!.onReceiveValue(
          WebChromeClient.FileChooserParams.parseResult(
            resultCode,
            intent
          )
        )
        uploadMessage = null
      }
    } else if (requestCode == FILECHOOSER_RESULTCODE) {
      if (null == mUploadMessage) return
      // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
      // Use RESULT_OK only if you're implementing WebView inside an Activity
//      val result: Uri? =
//        if (intent == null || resultCode != WebViews.RESULT_OK) null else intent.data
//      mUploadMessage.onReceiveValue(result)
      mUploadMessage = null
    }
  }


  private class xWebViewClient : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean {
      if (url != null) {
        view.loadUrl(url)
      }
      return true
    }
  }    
}

Is there a way to make it work as composable? Thanks

CodePudding user response:

Can we embed activity inside composable

Not really.

If the activity you are trying to start is from some third-party app, or is yours but is not written in Compose UI, the best that you can do is try activity embedding on Android 12L and higher.

If the activity that you are trying to start is your own, and it itself is built in Compose UI, you could get rid of that activity and navigate to its composable.

CodePudding user response:

You can try to reference the activity through an extenstion function:

inline fun <reified Activity : ComponentActivity> Context.getActivity(): Activity? {
    return when (this) {
        is Activity -> this
        else -> {
            var context = this
            while (context is ContextWrapper) {
                context = context.baseContext
                if (context is Activity) return context
            }
            null
        }
    }
}

Usage:

@Composable
fun YourComposable() {

    val activity = LocalContext.current.getActivity<MainActivity>()
}

CodePudding user response:

I think a good way of approaching your solution is just to hoist the open of the webview outside your composable

Example

class MainActivity() {
  setContent {
           YourComposable(param1, param2) { 
            openWebViewCallBack
          }
   }
}


@Composable
fun YourComposable(param1:Int, param2:String, onWebViewOpen: (url:String) -> Unit) { ... }
  • Related