Android WebView orqali JavaScript-dan Java funksiyasini chaqiring

Men Android ilovamdagi ba'zi Java kodlariga sinxron qo'ng'iroq qilmoqchiman.

Men ushbu yechimdan foydalanmoqdaman: https://stackoverflow.com/a/3338656

Mening Java kodim:

final class MyWebChromeClient extends WebChromeClient {
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            Log.d("LogTag", message);
            result.confirm();
            return true;
        }
    }

Mening JavaScript kodim:

<html>
<script>
function java_request(){
    alert('test');
}
</script>
<body>
<h2>Welcome</h2>
<div id="area"></div>
<form>
<input type="button" value="java_call" onclick="java_request()">
</form>
</body>
</html>

java_call tugmasini bosganimda tugma bosilgan holatga o'tadi. Men konsol jurnalida 'test' ni ko'rishim mumkin. Bu yergacha hammasi normal.

Muammo shundaki, tugma hech qachon normal holatiga qaytmaydi. U bosilgan holatda qoladi. Ehtimol, JavaScript-ning bajarilishi buzilgan yoki biror narsa?

Nima uchun tugma hech qachon normal holatiga qaytmaydi?


person ozkolonur    schedule 30.04.2012    source manba


Javoblar (3)


Bu java kodini bajarish uchun javascriptni olishning eng yaxshi yechimi deb o'ylamayman. Bu yerga qarang:

Agar siz JavaScript orqali qo'ng'iroq qilish mumkin bo'lgan HTML-ga mahalliy kodni ochishni istasangiz, veb-ko'rinish deklaratsiyasida quyidagilarni bajaring:

JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");

JavaScriptInterface sinfini e'lon qiling:

public class JavaScriptInterface {
    private Activity activity;

    public JavaScriptInterface(Activity activity) {
        this.activity = activity;
    }

    @JavascriptInterface
    public void startVideo(String videoAddress){
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse(videoAddress), "video/3gpp"); 
        activity.startActivity(intent);
    }
}

Men videoni o'ynash uchun yagona funktsiyani e'lon qilaman, lekin siz xohlagan narsani qilishingiz mumkin.

Nihoyat, siz buni WebView mazmunida oddiy javascript chaqiruvi orqali chaqirasiz:

<video width="320" height="240" controls="controls" poster='poster.gif'
       onclick="window.JSInterface.startVideo('file:///sdcard/test.3gp');" >
   Your browser does not support the video tag.
</video>

Misol videolarni o'ynash haqida mening boshqa javobimdan olingan, ammo etarlicha tushuntirish kerak.

EDIT @CedricSoubrie sharhiga ko'ra: agar ilovaning maqsadli versiyasi 17 yoki undan yuqori bo'lsa, veb-ko'rinishga eksport qilmoqchi bo'lgan har bir usulning ustiga @JavascriptInterface izohini qo'shishingiz kerak.

person Boris Strandjev    schedule 30.04.2012
comment
ma'lumot uchun rahmat, men bu yechimni ko'rdim. Ushbu yechim uchun 2.3.X da xatolik borligi sababli, men undan foydalanishni xohlamayman. vaqtinchalik yechim juda ajoyib edi. - person ozkolonur; 02.05.2012
comment
@ozkolonur Men buni Android 2.2+ ning barcha versiyalarida ishlatganman, hech qachon xato ko'rmaganman. Bu nima ekanligini baham ko'rishingiz mumkin. Havola ham juda xush kelibsiz. - person Boris Strandjev; 03.05.2012
comment
Menimcha, "playVideo" va "startVideo" bir xil bo'lishi kerakmi? - person Maarten; 19.12.2012
comment
@Maarten: aslida bu mening javobimdagi yagona xato emas edi. Men buni hozir tuzatdim. - person Boris Strandjev; 19.12.2012
comment
@BorisStrandjev Juda aniq javob! Esda tutingki, 17 yoki undan yuqori versiyalar uchun JavaScript-da mavjud boʻlishini istagan har qanday usulga @JavascriptInterface izohini qoʻshishingiz kerak. Manba: developer.android.com/guide/webapps/webview.html - person CedricSoubrie; 21.04.2013
comment
@CedricSoubrie: Aniq bo'lish uchun: agar maqsadli versiya 17 yoki undan yuqori bo'lsa (telefonning OS versiyasi emas) izoh talab qilinadi. Btw bu versiya men javobimni joylashtirganimda mavjud emas edi :) - person Boris Strandjev; 22.04.2013
comment
@BorisStrandjev: Agar xavfsizlik masalasi ustuvor bo'lsa, JavaScriptInterface ko'prigidan foydalanish eng yaxshi yechim emas. JavaScript-dan Android-ga o'tish uchun onJsAlert() yoki onConsoleMessage() dan foydalanish o'rniga ishonchliroq ko'rinadi. Bundan tashqari, evaluateJavascript() xuddi shu funksiya uchun API level19+ dan foydalanish mumkin. - person r.bhardwaj; 19.05.2014
comment
@r.bhardwaj bu haqda batafsil ma'lumot bera olasizmi? Ushbu yondashuvdan foydalanishda xavfsizlikka qanday xavflar bor? Biror joyga havola qila olasizmi? - person Boris Strandjev; 19.05.2014
comment
comment
@r.bhardwaj Havola uchun rahmat. Tushunishimcha, agar siz barcha kontentga ega boʻlmasangiz, xavf bor, bu ayniqsa, WebView ilovaning javesini suiisteʼmol qilishi mumkin boʻlgan uchinchi tomon kontentiga ega boʻlishi mumkin. Sizningcha, to'liq tarkibga ega bo'lgan holatlar xavfsizmi? - person Boris Strandjev; 19.05.2014
comment
@BorisStrandjev: Xavf asosan veb-ko'rinishda ishonchsiz kontentni yuklashni o'z ichiga olganligi to'g'ri. Sizning veb-ko'rinishingizga boshqa hujumlar ham bo'lishi mumkin (masalan, proksi-serverlar, ushbu sahifalar reklama tarmoqlari yoki boshqa uchinchi tomon manbalari orqali xizmat ko'rsatadigan yomon JS). - person r.bhardwaj; 19.05.2014
comment
rahmat. Mukammal ishlaydi! - person Nagaraj Alagusundaram; 04.07.2014
comment
yaxshi post.. menga ko'p yordam bering - person Dhina k; 07.10.2015
comment
@simpleBob Internetga ulanish holati haqida mobil ilovamdan veb-ilovani xabardor qilish, tarmoq oflayn bo'lganda tarmoq qo'ng'iroqlarini o'chirish uchun url bilan birga voqealarni olishim mumkinmi? - person ; 23.06.2016
comment
@JusticeBauer Men savolni to'liq tushunmayapman. BroadcastReceiver tarmoq holatidagi o'zgarishlarni qayd etishi mumkin. Yuqoridagi javobimga ko'ra, buni WebView ga ko'paytirish mumkin - person Boris Strandjev; 25.06.2016
comment
Buni iOS-da nima qilish kerak? - person Alberto Acuña; 14.11.2018
comment
@AlbertoAcuña Kechirasiz, men iOS dasturchisi emasman. Ehtimol, siz yangi mavzuni boshlashingiz kerak (yoki allaqachon mavjud echimni qidiring). Menimcha, iOS maxsus sxemalar bilan ishlashni (masalan, myapp://) ro'yxatdan o'tkazadi va platforma qatlami bilan shu tarzda bog'lanadi; veb-ko'rinish bilan aloqa Android-ga juda o'xshaydi. Ammo, yana bir bor aytamanki, men iOS ishlab chiqaruvchisi emasman, shuning uchun men aytganlarim haqiqat deb va'da bermayman. - person Boris Strandjev; 14.11.2018
comment
import android.webkit.JavascriptInterface; qo'shishim kerak edi - person mikep; 11.12.2020

Sizning funktsiyangiz "haqiqiy" ni qaytaradi. Bu HTML kodingizning "onclick" xususiyatini rostga tenglashtiradi, shuning uchun tugma "bosilgan" bo'lib qoladi.

person R. Maynard    schedule 30.06.2014

"YourJavaScriptInterface" sinfida aniqlangan usullar, "@JavascriptInterface" bilan ochmoqchi bo'lgan har bir usulga izoh qoldirishni unutmang, aks holda usul ishga tushmaydi.

Masalan, quyidagi kod veb-koʻrish sahifasidan qoʻngʻiroqlar uchun Google Cloud Print JavaScript interfeysidan olingan:

        final class PrintDialogJavaScriptInterface {
        @JavascriptInterface
        public String toString() { return JS_INTERFACE; }

        @JavascriptInterface
        public String getType() {
            return cloudPrintIntent.getType();
        }

        @JavascriptInterface
        public String getTitle() {
            return cloudPrintIntent.getExtras().getString("title");
        }

        @JavascriptInterface
        public String getContent() {
            try {
                ContentResolver contentResolver = getActivity().getContentResolver();
                InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                byte[] buffer = new byte[4096];
                int n = is.read(buffer);
                while (n >= 0) {
                    baos.write(buffer, 0, n);
                    n = is.read(buffer);
                }
                is.close();
                baos.flush();

                return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }

        @JavascriptInterface
        public String getEncoding() {
            return CONTENT_TRANSFER_ENCODING;
        }

        @JavascriptInterface
        public void onPostMessage(String message) {
            if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
                finish();
            }
        }
    }
person tyolab    schedule 12.03.2018