针对跨应用脚本编写的 WebView URL 接收实践

如何解决针对跨应用脚本编写的 WebView URL 接收实践

没错,我的应用也因跨应用脚本而被 Google 删除。问题的一半可能是问题出在哪里,但我更关心的是“现代应用程序中接收菜单项的最佳实践是什么(包含传递给 webview 的 ListTile 和图块 URL 的标题的对象)”。

我的应用目前有一个 2 列的卡片回收站视图。应用程序从 Google Firestore 接收所有文档,将它们转换为对象并在 recyclerview 中显示它们。一旦用户点击其中一张卡片,webview 就会打开,其中包含菜单中卡片中提供的 url。

自从 google 删除了我的应用程序后,我尝试禁用 javascript,但我明白它对于禁用 webviews 来说太重要了,所以我保持启用状态。我在清单中将每个活动更改为“exported=false”,并添加一个用于安全 webview 的元标记,但所有这些都没有完成谷歌接受它的工作,所以我想知道是否要在应用程序中对 firebase 信息进行硬编码,但是会弄乱应用程序的主要思想,这很容易从任何地方和任何人进行管理,而无需 IT 人员对应用程序进行硬编码。 附注我知道谷歌将我的 firestore-info-to-webviews 关系视为一个巨大的安全漏洞,因此我不知道现在该怎么做才能让我的应用重新收费。

这里有一些代码来看看我得到的东西:

在我跳入代码之前,这是我按下菜单中的卡片/项目之一时的样子 - 网页视图打开并加载卡片提供的网址:

enter image description here

好的,现在让我们进入代码。首先,应用程序的清单文件

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="viaapp_v2">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:anyDensity="true" />
    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme.ViaTheme"
        android:usesCleartextTraffic="true">
        <activity
            android:name=".systems.webview_activity.webview_base"
            android:configChanges="orientation|screenSize"
            android:parentActivityName=".main_screen.MenuScreen"
            android:label="@string/title_webview">
            <Meta-data android:name="android.webkit.WebView.EnableSafebrowsing"
                android:value="true" />
            <intent-filter>
                <category android:name="android.intent.category.broWSABLE" />
                <action android:name="android.intent.action.VIEW" />

                <data android:scheme="file" />
                <data android:mimeType="\*/\*" />
                <data android:pathPattern=".*\\.kdb" />
                <data android:host="*" />
            </intent-filter>
        </activity>
        <activity
            android:name="viaapp_v2.main_screen.MenuScreen"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:launchMode="singleTask"
            android:label="@string/title_activity_menu_screen" />
  
    </application>

</manifest>

2nd - 菜单项对象类:

public class MenuObject {
    String title;
    String icon_url;
    String webURL;
    String activity;
    int bgcolor;

    //constructor to lead to webview activity
    public MenuObject(String title,String icon_url,String webURL,String activity) {
        this.title = title;
        this.icon_url = icon_url;
        this.webURL = webURL;
        this. activity = activity;
        Log.i("MenuObject","Object "+title+" created");
    }

    //constructor to lead to lecture graph
    public MenuObject(String title,String activity) {
        this.title = title;
        this.icon_url = icon_url;
        this. activity = activity;
        Log.i("MenuObject","Object "+title+" created");
    }

    //WITH BACKGROUND COLOR

    //constructor to lead to webview activity
    public MenuObject(String title,String activity,int bgcolor) {
        this.title = title;
        this.icon_url = icon_url;
        this.webURL = webURL;
        this. activity = activity;
        this.bgcolor = bgcolor;
        Log.i("MenuObject","Object "+title+" created with bgcolor "+bgcolor);
    }

    //constructor to lead to lecture graph
    public MenuObject(String title,int bgcolor) {
        this.title = title;
        this.icon_url = icon_url;
        this. activity = activity;
        this.bgcolor = bgcolor;
        Log.i("MenuObject","Object "+title+" created with bgcolor "+bgcolor);
    }

    public String getActivity() {
        return activity;
    }

    public String getTitle() {
        return title;
    }

    public String getIcon_url() {
        return icon_url;
    }

    public String getWebURL() {
        return webURL;
    }

    public int getColor() {
        return bgcolor;
    }

}

最后一个,webview 基础:

public class webview_base extends AppCompatActivity {
    String url;
    WebView webview_Box;
    View root;
    private static final String TAG = webview_base.class.getSimpleName();
    private ValueCallback<Uri[]> mUploadMessage;
    private FloatingActionButton leave_page,webview_goBack,webview_goForward;
    private final static int FILECHOOSER_RESULTCODE = 1;

    @Override
    protected void onRestart() {
        super.onRestart();
    }

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview_base);
        root = getwindow().getDecorView().getRootView();


        leave_page = findViewById(R.id.leave_webview);
        leave_page.setonClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                returnToMenu();
            }
        });

        webview_Box = findViewById(R.id.webview_Box);
        WebSettings webSettings = webview_Box.getSettings();
//        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        webSettings.setJavaScriptEnabled(true);
//        webSettings.setAllowFileAccess(true);
//        webSettings.setSupportMultipleWindows(true);
//        webSettings.setAllowContentAccess(true);
//        webSettings.setDatabaseEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setAppCacheEnabled(false);
        webSettings.setSavePassword(true);
        webSettings.setSaveFormData(true);
        webSettings.setAppCacheMaxSize(0);
        webSettings.setAllowFileAccess(false);
        webSettings.setAppCacheEnabled(false);
//        webSettings.setUseWideViewPort(true);
//        webSettings.setLoadWithOverviewmode(true);
//        webSettings.setDatabasePath("/data/data/" + getPackageName() + "/databases/");
        webview_Box.setWebChromeClient(new MyChromeClient());
        webview_Box.setDownloadListener(new DownloadListener() {

            @Override
            public void onDownloadStart(String url,String userAgent,String contentdisposition,String mimeType,long contentLength) {


                //if they are granted
                if(hasstoragePermissions(webview_base.this)){
                    //if perms are granted,starts file download
                    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
                    request.setMimeType(mimeType);
                    String cookies = CookieManager.getInstance().getCookie(url);
                    request.addRequestHeader("cookie",cookies);
                    request.addRequestHeader("User-Agent",userAgent);
                    request.setDescription(getString(R.string.downloading_file));
                    request.setTitle(URLUtil.guessFileName(url,contentdisposition,mimeType));
                    request.allowScanningByMediaScanner();
                    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,URLUtil.guessFileName(url,mimeType));
                    DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
                    dm.enqueue(request);

                    //make toast notifying for dile download
                    Toast.makeText(getApplicationContext(),getString(R.string.downloading_file),Toast.LENGTH_LONG).show();
                }
            }
        });
        CookieManager.getInstance().acceptCookie();

        //if SDK version is greater of 19 then activate hardware acceleration otherwise activate software acceleration
        if (Build.VERSION.SDK_INT >= 19) {
            webview_Box.setLayerType(View.LAYER_TYPE_HARDWARE,null);
        } else {
            webview_Box.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
        }

        if (savedInstanceState == null) {
            Bundle extras = getIntent().getExtras();
            if(extras == null) {
                //close webview doe to error
                Log.e("WEBVIEW_BASE","No URL passed in extras");
                returnToMenu();
            } else {
                //open notification url
                    if(extras.getString("web_url") != null) url = extras.getString("web_url");
                //otherwise open menu provided url
                else url = extras.getString("link");
            }
        } else {
            url = (String) savedInstanceState.getSerializable("link");
        }

        webview_Box.setWebViewClient(new WebViewClient() {
            @Override public void onReceivedSslError(WebView v,final SslErrorHandler handler,SslError er){

                new AlertDialog.Builder(webview_base.this)
                        .setTitle(getString(R.string.warning))
                        .setMessage(getString(R.string.insecure_source))

                        //if user clicks to proceed to site
                        .setPositiveButton(getString(R.string.proceed),new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,int which) {
                                handler.proceed();
                            }
                        })

                        //if user clicks to leave the site loading process
                        .setNegativeButton(getString(R.string.terminate_page_load),new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,int which) {
                                webview_Box.goBack();
                            }
                        })
                        .setIcon(R.drawable.via)
                        .show();
            }

            @Override
            public void onReceivedError(WebView view,WebResourceRequest request,WebResourceError error){
                show_web_error();
                Log.e("Web loading error",error.toString());
            }

            //Show loader on url load
            public void onPageStarted(WebView view,String url,Bitmap favicon) {
                enable_web_loading_screen();
            }

            // Called when all page resources loaded
            public void onPageFinished(WebView view,String url) {
                //hides splashscreen with animation
                hide_web_loading_screen();
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view,String url) {

                // If url contains mailto link then open Mail Intent
                if (url.contains("tel:") || url.contains("sms:") || url.contains("smsto:") || url.contains("mailto:") || url.contains("mms:") || url.contains("mmsto:")) {

                    // Could be cLeverer and use a regex
                    //Open links in new browser
                    view.getContext().startActivity(
                            new Intent(Intent.ACTION_VIEW,Uri.parse(url)));

                } else {
                    // Stay within this webview and load url
                    webview_Box.loadUrl(url);
                }
                return true;
            }
        });

        //laods passed URL from notification,load overwritten url
       webview_Box.loadUrl(url);

       //goBack FAB listener
        webview_goBack = findViewById(R.id.webview_goBack);
        webview_goBack.setonClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(webview_Box.canGoBack())webview_Box.goBack();
            }
        });

        //goForward FAB listener
        webview_goForward = findViewById(R.id.webview_goForward);
        webview_goForward.setonClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(webview_Box.canGoForward())webview_Box.goForward();
            }
        });
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig){
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void onActivityResult(int requestCode,int resultCode,Intent data) {
        super.onActivityResult(requestCode,resultCode,data);
        if (requestCode == FILECHOOSER_RESULTCODE) {

            if (null == mUploadMessage || data == null || resultCode != RESULT_OK) {
                return;
            }

            Uri[] result = null;
            String dataString = data.getDataString();

            if (dataString != null) {
                result = new Uri[]{Uri.parse(dataString)};
            }

            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,@NonNull String[] permissions,@NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode,permissions,grantResults);
        int i = 0;
        boolean is_good = true;

        for(String permission : permissions){
            //check if any of permissions were declined
            if(grantResults[i] == PackageManager.PERMISSION_DENIED){
                //notify for any ungranted perms
                is_good = false;
                break;
            }
            i++;
        }

        if(!is_good){
            Snackbar.make(root,R.string.ungranted_perms,Snackbar.LENGTH_LONG).show();
        }else {
            Snackbar.make(root,R.string.granted_perms,Snackbar.LENGTH_LONG).show();
        }
    }

    public static boolean hasstoragePermissions(Activity activity) {
        // Check if we have read or write permissions for download/uplaod options
        int writePermission = ActivityCompat.checkSelfPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int readPermission = ActivityCompat.checkSelfPermission(activity,Manifest.permission.READ_EXTERNAL_STORAGE);

        boolean result = true;
        //if permission is not granted
        if(writePermission != PackageManager.PERMISSION_GRANTED || readPermission != PackageManager.PERMISSION_GRANTED){
            //request permission
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},101);
            //recheck permission
            if(ActivityCompat.checkSelfPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE)  != PackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(activity,Manifest.permission.READ_EXTERNAL_STORAGE)  != PackageManager.PERMISSION_GRANTED) result = false;
        }
        //return permission status
        return result;
    }

    public class MyChromeClient extends WebChromeClient {


        @Override
        public boolean onShowFileChooser(WebView webView,ValueCallback<Uri[]> filePathCallback,FileChooserParams fileChooserParams) {

            // asegurar que no existan callbacks
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(null);
            }

            mUploadMessage = filePathCallback;

            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*"); // set MIME type to filter

            webview_base.this.startActivityForResult(Intent.createChooser(i,"File Chooser"),webview_base.FILECHOOSER_RESULTCODE );

            return true;
        }
    }

    public boolean onKeyDown(int keyCode,KeyEvent event) {
        // Check if the key event was the Back button and if there's history
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webview_Box.canGoBack()) {
            webview_Box.goBack();
            return true;
        }
        // If it wasn't the Back key or there's no web page history,bubble up to the default
        // system behavior (probably exit the activity)

        return super.onKeyDown(keyCode,event);
    }

    @Override
    public void onBackpressed() {
        if (webview_Box.canGoBack()) {
            webview_Box.goBack();
        } else {
            returnToMenu();
        }
    }

    private void GoForward() {
        if (webview_Box.canGoForward()) {
            webview_Box.goForward();
        }
    }


    private void enable_web_loading_screen(){
        Log.d("Web loading","started");
        //opens splashscreen
        root.findViewById(R.id.via_splash_screen_3).setVisibility(View.VISIBLE);
        root.findViewById(R.id.splash_screen_progress_3).setVisibility(View.VISIBLE);
    }

    private void hide_web_loading_screen(){
        Log.d("Web loading","finished");
        //hides splashscreen with animation
        root.findViewById(R.id.via_splash_screen_3).setAnimation(AnimationUtils.loadAnimation(webview_base.this,R.anim.disappear));
        root.findViewById(R.id.via_splash_screen_3).setVisibility(View.GONE);
        root.findViewById(R.id.splash_screen_progress_3).setVisibility(View.GONE);
    }

     private void show_web_error() {
     //if any other error occurs
     Snackbar.make(findViewById(R.id.web_base_view),getText(R.string.web_error_text),Snackbar.LENGTH_INDEFINITE)

             .setAction(getString(R.string.reload_page),new View.OnClickListener() {
                 @Override
                 public void onClick(View view) {
                     WebView web = findViewById(R.id.webview_Box);
                     web.loadUrl(url);
                     enable_web_loading_screen();
                 }
             })
             .setActionTextColor(getResources().getColor(android.R.color.holo_red_light ))
             .show();
    }

    public void returnToMenu(){
        finish();
        //brings to top or opens a new home activity
        startActivity(new Intent(webview_base.this,MenuScreen.class));
    }
}

很高兴在这里听到您对我的问题的意见。 干杯。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?