> For the complete documentation index, see [llms.txt](https://docs.caf.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.caf.io/caf-docs/caf-product-guides-pt-br/guias-de-inicio-rapido/onboardings-integration/webview/webview_android.md).

# Android

### Manifesto do Android

Adicione estas linhas ao arquivo AndroidManifest.xml no módulo do seu app:

```xml
<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```

### Android WebView (Kotlin)

Este é um exemplo de uma activity usando uma WebView

```kotlin
class WebViewActivity : AppCompatActivity() {
    private var filePathCallback: ValueCallback<Array<Uri>>? = null
    private var permissionRequest: PermissionRequest? = null
    private lateinit var webView: WebView

    private val url = "https://cadastro.io/:token"

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

        this.webView = getWebView()
        setContentView(webView)
        webView.loadUrl(url)
    }

    private fun getWebView(): WebView {
        val webView = WebView(this)
        val webSettings = webView.settings
        webSettings.javaScriptEnabled = true
        webSettings.domStorageEnabled = true
        webSettings.mediaPlaybackRequiresUserGesture = false
        webSettings.javaScriptCanOpenWindowsAutomatically = true
        webSettings.loadWithOverviewMode = true
        webSettings.useWideViewPort = true
        webSettings.allowFileAccess = true
        webSettings.allowContentAccess = true
        webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
        webView.webChromeClient = MyWebChromeClient()
        webView.webViewClient = WebViewClient()
        return webView
    }

    /**
     * O resultado da solicitação de permissão é tratado aqui.
     * Se a permissão for concedida, a webView é carregada.
     */
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String?>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == CAMERA_REQUEST_CODE && grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            permissionRequest?.grant(permissionRequest?.resources)
        } else {
            permissionRequest?.deny()
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
            if (filePathCallback == null) {
                return
            }
            val results = WebChromeClient.FileChooserParams.parseResult(resultCode, data)
            filePathCallback!!.onReceiveValue(results)
            filePathCallback = null
        }
    }

    private inner class MyWebChromeClient : WebChromeClient() {
        var originalOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
        var originalVisibility: Int = View.INVISIBLE
        private var customView: View? = null
        private var customViewCallback: CustomViewCallback? = null

        override fun onPermissionRequest(request: PermissionRequest) {
            val requestedAndroidPermissions = ArrayList<String>()
            for (requestedResource in request.resources) {
                if (requestedResource == PermissionRequest.RESOURCE_VIDEO_CAPTURE &&
                    ContextCompat.checkSelfPermission(
                        this@WebViewActivity.applicationContext,
                        Manifest.permission.CAMERA
                    ) != PackageManager.PERMISSION_GRANTED) {
                    requestedAndroidPermissions.add(Manifest.permission.CAMERA)
                }
            }
            if (requestedAndroidPermissions.isEmpty()) {
                request.grant(request.resources)
                return
            }
            permissionRequest = request
            requestPermissions(
                requestedAndroidPermissions.toTypedArray<String>(),
                CAMERA_REQUEST_CODE
            )
        }

        /**
         * O callback informará ao aplicativo host que a página atual desejaria
         * exibir uma View personalizada em uma orientação específica
         */
        override fun onShowCustomView(view: View, callback: CustomViewCallback) {
            if (customView != null) {
                onHideCustomView()
                return
            }
            customView = view
            originalVisibility = window.decorView.systemUiVisibility
            originalOrientation = requestedOrientation
            (window.decorView as FrameLayout).addView(
                customView,
                FrameLayout.LayoutParams(-1, -1)
            )
            // Isso garantirá que a view personalizada esteja em modo de tela cheia
            window.decorView.systemUiVisibility = 3846 or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
        }

        /**
         * O callback informará ao aplicativo host que a página atual saiu do modo de tela cheia,
         * e o app precisa ocultar a view personalizada.
         */
        override fun onHideCustomView() {
            (window.decorView as FrameLayout).removeView(customView)
            customView = null
            window.decorView.systemUiVisibility = originalVisibility
            requestedOrientation = originalOrientation
            if (customViewCallback != null) {
                customViewCallback!!.onCustomViewHidden()
            }
            customViewCallback = null
        }

        override fun onShowFileChooser(
            webView: WebView,
            filePathCallback: ValueCallback<Array<Uri>>,
            fileChooserParams: FileChooserParams
        ): Boolean {
            if (this@WebViewActivity.filePathCallback != null) {
                this@WebViewActivity.filePathCallback?.onReceiveValue(null)
            }
            this@WebViewActivity.filePathCallback = filePathCallback

            val intent = fileChooserParams.createIntent()
            try {
                startActivityForResult(intent, FILE_CHOOSER_REQUEST_CODE)
            } catch (e: ActivityNotFoundException) {
                this@WebViewActivity.filePathCallback = null
                return false
            }
            return true
        }
    }

    companion object {
        private const val CAMERA_REQUEST_CODE = 1001
        private const val FILE_CHOOSER_REQUEST_CODE = 1002
    }
}
```

### Android WebView (Java)

```java
public class WebViewActivity extends AppCompatActivity {

    private ValueCallback<Uri[]> filePathCallback;
    private WebView webView;
    private PermissionRequest permissionRequest;
    private static final String url = "https://cadastro.io/:token";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.webView = getWebView();
        setContentView(webView);
        webView.loadUrl(url);
    }

    private WebView getWebView() {
        WebView webView = new WebView(this);
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setMediaPlaybackRequiresUserGesture(false);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setUseWideViewPort(true);
        webSettings.setAllowFileAccess(true);
        webSettings.setAllowContentAccess(true);
        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        webView.setWebChromeClient(new MyWebChromeClient());
        webView.setWebViewClient(new WebViewClient());
        return webView;
    }

    /**
     * O resultado da solicitação de permissão é tratado aqui.
     * Se a permissão for concedida, a webView é carregada.
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == CAMERA_REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            if (permissionRequest != null) {
                permissionRequest.grant(permissionRequest.getResources());
            }
        } else {
            if (permissionRequest != null) {
                permissionRequest.deny();
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
            if (filePathCallback == null) {
                return;
            }
            Uri[] results = WebChromeClient.FileChooserParams.parseResult(resultCode, data);
            filePathCallback.onReceiveValue(results);
            filePathCallback = null;
        }
    }

    private class MyWebChromeClient extends WebChromeClient {
        private int originalOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
        private int originalVisibility = View.INVISIBLE;
        private View customView;
        private CustomViewCallback customViewCallback;

        @Override
        public void onPermissionRequest(PermissionRequest request) {
            ArrayList<String> requestedAndroidPermissions = new ArrayList<>();
            for (String requestedResource : request.getResources()) {
                if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE) &&
                        ContextCompat.checkSelfPermission(
                                WebViewActivity.this,
                                android.Manifest.permission.CAMERA
                        ) != PackageManager.PERMISSION_GRANTED) {
                    requestedAndroidPermissions.add(android.Manifest.permission.CAMERA);
                }
            }
            permissionRequest = request;
            if (requestedAndroidPermissions.isEmpty()) {
                request.grant(request.getResources());
                return;
            }
            requestPermissions(requestedAndroidPermissions.toArray(new String[0]), CAMERA_REQUEST_CODE);
        }

        /**
         * O callback informará ao aplicativo host que a página atual desejaria
         * exibir uma View personalizada em uma orientação específica
         */
        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            if (customView != null) {
                onHideCustomView();
                return;
            }
            customView = view;
            originalVisibility = getWindow().getDecorView().getSystemUiVisibility();
            originalOrientation = getRequestedOrientation();
            ((FrameLayout) getWindow().getDecorView()).addView(
                    customView,
                    new FrameLayout.LayoutParams(-1, -1)
            );
            // Isso garantirá que a view personalizada esteja em modo de tela cheia
            getWindow().getDecorView().setSystemUiVisibility(3846 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
        }

        /**
         * O callback informará ao aplicativo host que a página atual saiu do modo de tela cheia,
         * e o app precisa ocultar a view personalizada.
         */
        @Override
        public void onHideCustomView() {
            ((FrameLayout) getWindow().getDecorView()).removeView(customView);
            customView = null;
            getWindow().getDecorView().setSystemUiVisibility(originalVisibility);
            setRequestedOrientation(originalOrientation);
            if (customViewCallback != null) {
                customViewCallback.onCustomViewHidden();
            }
            customViewCallback = null;
        }

        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
            if (WebViewActivity.this.filePathCallback != null) {
                WebViewActivity.this.filePathCallback.onReceiveValue(null);
            }
            WebViewActivity.this.filePathCallback = filePathCallback;

            Intent intent = fileChooserParams.createIntent();
            try {
                startActivityForResult(intent, FILE_CHOOSER_REQUEST_CODE);
            } catch (ActivityNotFoundException e) {
                WebViewActivity.this.filePathCallback = null;
                return false;
            }
            return true;
        }
    }

    private static final int CAMERA_REQUEST_CODE = 1001;
    private static final int FILE_CHOOSER_REQUEST_CODE = 1002;
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.caf.io/caf-docs/caf-product-guides-pt-br/guias-de-inicio-rapido/onboardings-integration/webview/webview_android.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
