티스토리 뷰

반응형

Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.

Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.

 

아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.

android webview geolocation

안드로이드 웹뷰에서 위치정보 사용하기

 문제 내용 

I have to retrieve a user's location in a WebView. I do this with the following Javascript:

제가 웹뷰에서 사용자 위치를 검색해야합니다. 저는 다음과 같은 자바스크립트를 사용합니다:
function getLocation() {
   navigator.geolocation.getCurrentPosition(displayLocation, handleError);
}

 

But the permission request popup never opens.

하지만 권한 요청 팝업이 열리지 않습니다.

 

I've set these settings:

제가 설정한 것들은 다음과 같습니다:
ws.setJavaScriptEnabled(true);
ws.setGeolocationEnabled(true);
ws.setJavaScriptCanOpenWindowsAutomatically(true);

 

What is the correct way to access a user's location from within a WebView?

WebView에서 사용자 위치에 올바르게 액세스하는 방법은 무엇인가요?

 

 

 

 높은 점수를 받은 Solution 

  • JavaScript must be enabled in the WebView, using WebSettings.setJavaScriptEnabled(true);
  • The app needs permission ACCESS_FINE_LOCATION
  • The WebView must use a custom WebChromeClient which implements WebChromeClient.onGeolocationPermissionsShowPrompt(). This method is called by the WebView to obtain permission to disclose the user's location to JavaScript. (In the case of the browser, we show a prompt to the user.) The default implementation does nothing, so permission is never obtained and the location is never passed to JavaScript. A simple implementation which always grants permission is ...
  • webView.setWebChromeClient(new WebChromeClient() { public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { callback.invoke(origin, true, false); } });
WebView에서 JavaScript를 사용하려면 WebSettings.setJavaScriptEnabled(true)로 JavaScript가 활성화되어야합니다.

앱은 ACCESS_FINE_LOCATION 권한이 필요합니다.

WebView는 WebChromeClient.onGeolocationPermissionsShowPrompt()를 구현하는 사용자 정의 WebChromeClient를 사용해야합니다. 이 메서드는 WebView에서 JavaScript에게 사용자 위치를 공개 할 권한을 요청하는 데 사용됩니다. (브라우저의 경우 사용자에게 프롬프트를 표시합니다.) 기본 구현은 아무것도하지 않으므로 권한이 부여되지 않고 위치가 JavaScript로 전달되지 않습니다. 항상 권한을 부여하는 간단한 구현은 다음과 같습니다. ...

 

Geolocation uses databases to persist cached positions and permissions between sessions. The location of the database is set using WebSettings.setGeolocationDatabasePath(...). If the location of the database is not set, the persistent storage will not be available, but Geolocation will continue to function correctly otherwise. To set the location of the databases, use ...

위치 정보는 캐시 된 위치와 권한을 세션간에 유지하기 위해 데이터베이스를 사용합니다. 데이터베이스의 위치는 WebSettings.setGeolocationDatabasePath(...)를 사용하여 설정됩니다. 데이터베이스의 위치가 설정되지 않으면 영구 저장소는 사용할 수 없지만 지리 위치 기능은 그 외에도 제대로 작동합니다. 데이터베이스의 위치를 설정하려면 ...를 사용하세요.
webView.getSettings().setGeolocationDatabasePath( context.getFilesDir().getPath() );

 

 

 가장 최근 달린 Solution 

I have recently come across this type of situation and have done below steps to achieve this:

저는 최근에 이러한 유형의 상황을 겪었고 아래 단계를 수행하여 이것을 달성했습니다.

 

Step 1: Add permissions in your AndroidManifest.xml file

1단계: AndroidManifest.xml 파일에 권한 추가
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

 

Step 2: Create an activity that would contain a WebView and ProgressBar (in my case)

2 단계: WebView와 ProgressBar (내 경우)가 포함 된 액티비티를 만듭니다.
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="0dp"
        android:minHeight="4dp"
        android:padding="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <WebView
        android:id="@+id/webView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progressBar" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

Step 3: In your activity class, add below code and make changes according to your need

3 단계: 액티비티 클래스에 아래 코드를 추가하고 필요에 따라 변경합니다.
class WebActivity : AppCompatActivity() {
    var pageUrl: String = "https://couponia.co/"
    var mGeoLocationRequestOrigin: String? = null
    var mGeoLocationCallback: GeolocationPermissions.Callback? = null
    val MAX_PROGRESS = 100
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_web)
        initWebView()
        setWebClient()
        loadUrl(pageUrl)
    }


    @SuppressLint("SetJavaScriptEnabled")
    private fun initWebView() {
        webView.settings.javaScriptEnabled = true
        webView.settings.loadWithOverviewMode = true
        webView.settings.useWideViewPort = true
        webView.settings.domStorageEnabled = true
        webView.settings.databaseEnabled = true
        webView.settings.setAppCacheEnabled(true)
        webView.webViewClient = object : WebViewClient() {
            override
            fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
                handler?.proceed()
            }
        }

    }

    private fun setWebClient() {

        webView.webChromeClient = object : WebChromeClient() {
            override fun onGeolocationPermissionsShowPrompt(
                origin: String?,
                callback: GeolocationPermissions.Callback?
            ) {

                if (ContextCompat.checkSelfPermission(
                        this@WebActivity,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    )
                    != PackageManager.PERMISSION_GRANTED
                ) {

                    if (ActivityCompat.shouldShowRequestPermissionRationale(
                            this@WebActivity,
                            Manifest.permission.ACCESS_FINE_LOCATION
                        )
                    ) {
                        AlertDialog.Builder(this@WebActivity)
                            .setMessage("Please turn ON the GPS to make app work smoothly")
                            .setNeutralButton(
                                android.R.string.ok,
                                DialogInterface.OnClickListener { dialogInterface, i ->
                                    mGeoLocationCallback = callback
                                    mGeoLocationRequestOrigin = origin
                                    ActivityCompat.requestPermissions(
                                        this@WebActivity,
                                        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001
                                    )

                                })
                            .show()

                    } else {
                        //no explanation need we can request the locatio
                        mGeoLocationCallback = callback
                        mGeoLocationRequestOrigin = origin
                        ActivityCompat.requestPermissions(
                            this@WebActivity,
                            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001
                        )
                    }
                } else {
                    //tell the webview that permission has granted
                    callback!!.invoke(origin, true, true)
                }

            }

            override fun onProgressChanged(view: WebView?, newProgress: Int) {
                super.onProgressChanged(view, newProgress)
                progressBar.progress = newProgress
                if (newProgress < MAX_PROGRESS && progressBar.visibility == ProgressBar.GONE) {
                    progressBar.visibility = ProgressBar.VISIBLE
                }
                if (newProgress == MAX_PROGRESS) {
                    progressBar.visibility = ProgressBar.GONE
                }
            }


        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        // Check if the key event was the Back button and if there's history
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack()
            return true
        }
        // If it wasn't the Back key or there's no web page history, exit the activity)
        return super.onKeyDown(keyCode, event)
    }

    private fun loadUrl(pageUrl: String) {
        webView.loadUrl(pageUrl)
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        when (requestCode) {
            1001 -> {
                //if permission is cancel result array would be empty
                if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //permission was granted
                    if (mGeoLocationCallback != null) {
                        mGeoLocationCallback!!.invoke(mGeoLocationRequestOrigin, true, true)
                    }
                } else {
                    //permission denied
                    if (mGeoLocationCallback != null) {
                        mGeoLocationCallback!!.invoke(mGeoLocationRequestOrigin, false, false)
                    }
                }
            }

        }
    }
}

 

 

출처 : https://stackoverflow.com/questions/5329662/android-webview-geolocation

반응형
댓글
공지사항
최근에 올라온 글