在android中渲染epub书?

发布于 2024-12-21 08:48:48 字数 247 浏览 1 评论 0原文

我尝试在 android pad 中显示 epub 书。我可以解析html和css,以显示书的内容和格式,也许书包含图片,看来我有两个选择:

  1. 使用Webview。
  2. 编写一个客户视图,以便它可以渲染 html/css --- 这似乎是一个非常复杂的任务。

哪个是好方法?如果我必须使用WebView,那么分页逻辑怎么样,因为webview在一页中解析一个html文件,所以我在webview中找不到分页符。

I am try to show epub book in android pad. I can parse the html and css, in order to show the book's content and format, perhaps the book include pictures, It seems that I have two option:

  1. use Webview.
  2. Write a customer view, so that it can render html/css --- it seems a very complicated task.

Which is the good way? If I have to use WebView, how about the page break logic, since webview parse one html file in one page, I can not find the page break in webview.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧瑾黎汐 2024-12-28 08:48:48

我已经为 android 和 ios 开发了一个原生 epub 播放器

我在这里分享的代码是我的产品源代码的一部分,复制和粘贴它对你不起作用。当作参考吧。

我在android中使用了webview,在ios中使用了uiwebview来制作自定义视图并解析html/css几乎就像开发一个新的渲染引擎(即浏览器)一样。这是一个繁琐而复杂的过程。

简而言之,我向您介绍我在 android 中遵循的步骤

  • 创建自定义 webview
  • 加载 url 并
  • 在 webview 加载后使用以下方法编写分页回调

客户端(WebViewClient、WebChromeClient)代码:

private class MyWebClient extends WebViewClient
    {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }
        @Override
        public void onPageFinished(WebView view, String url) 
        {
            super.onPageFinished(view, url);

            final MyWebView myWebView = (MyWebView) view;

            String varMySheet = "var mySheet = document.styleSheets[0];";

                String addCSSRule = "function addCSSRule(selector, newRule) {"
                        + "ruleIndex = mySheet.cssRules.length;"
                        + "mySheet.insertRule(selector + '{' + newRule + ';}', ruleIndex);"

                        + "}";

                String insertRule1 = "addCSSRule('html', 'padding: 0px; height: "
                        + (myWebView.getMeasuredHeight()/getContext().getResources().getDisplayMetrics().density )
                        + "px; -webkit-column-gap: 0px; -webkit-column-width: "
                        + myWebView.getMeasuredWidth() + "px;')";

                myWebView.loadUrl("javascript:" + varMySheet);
                myWebView.loadUrl("javascript:" + addCSSRule);
                myWebView.loadUrl("javascript:" + insertRule1);



        }
    }

private class MyWebChromeClient extends WebChromeClient
    {
        @Override
        public void onProgressChanged(WebView view, int newProgress) 
        {
            super.onProgressChanged(view, newProgress);
            //  GlobalConstants.ENABLE_WEB_VIEW_TOUCH = false;
            if(newProgress == 100)
            {
                postDelayed(new Runnable() 
                {
                    @Override
                    public void run() 
                    {
                        calculateNoOfPages();

                    }
                },300);
            }
        }
    }

private void calculateNoOfPages()
    {

        if(getMeasuredWidth() != 0)
        {
            int newPageCount = computeHorizontalScrollRange()/getMeasuredWidth();
        }
    }

将 jquery.js 注入 webview:

private void addJQueryJS() 
    {
        String path = "file:///android_asset/JSLibraries/jquery.min.js";
        String data = "{\"MethodName\":\"onJQueryJSLoaded\",\"MethodArguments\":{}}";
        String callBackToNative  = " jsInterface.callNativeMethod('jstoobjc:"+data+"');";
        String script = "function includeJSFile()"
                               +"{"
                               +"function loadScript(url, callback)"
                               +"{"
                               +"var script = document.createElement('script');"
                               +"script.type = 'text/javascript';"
                               +"script.onload = function () {"
                               +"callback();"
                               +"};"
                               +"script.src = url;"
                               +"if(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])"
                               +"{"
                               +"(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);"
                               +"}"
                               +"else { callback(); }"
                               +"}"
                               +"loadScript('"+path+"', function ()"
                               +"{"
                               +callBackToNative
                               +"});"
                               +"} ; includeJSFile();";
        loadUrl("javascript: "+script);
    }
  • 将所有单词包装到 span 中 -用于突出显示文本和导航到页面。
  • 将会有 3 个 webview - 当前页面、下一页和上一页。您应该根据该章的页数设置 webview 滚动的偏移量。
    假设一个 .html 文件有 3 个页面的内容 - 前一个 webview 是第一页,当前 webview 是第二页,下一个 webview 是第三页,但所有 webview 加载相同的 url。但它们的内容偏移量不同。
  • 编写自己的页面滑动逻辑,而不是使用 viewpager。只需将当前页面传递给适配器,然后适配器将通过一些计算返回下一页和上一页。

代码:

@Override
    public PageView getPreviousView(PageView oldPage) 
    {
        MyWebView oldWebView = ((PageView)oldPage).getWebView();

        int chapterIndex = oldWebView.getData().getIndexOfChapter();
        int pageIndex = oldWebView.getData().getIndexOfPage();
        int pageCount = oldWebView.getData().getChapterVO().getPageCount();
        pageIndex--;
        if(pageIndex < 0)
        {
            pageIndex = 0;
            chapterIndex--;
            if(chapterIndex<0)
            {
                //return the same page
                chapterIndex = 0;
                return null;
            }
            else
            {
                //previous chapter last page
                PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                MyWebView webView= pageView.getWebView();

                PageVO data = new PageVO();
                data.setChapterVO(_chaptersColl.get(chapterIndex));
                data.setIndexOfChapter(chapterIndex);
                data.setIndexOfPage(-2);

                webView.setData(data);
                return pageView;
            }
        }
        else if(pageIndex <= pageCount-1)
        {
            //same chapter previous page
            PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
            MyWebView webView= pageView.getWebView();

            PageVO data = new PageVO();
            data.setChapterVO(_chaptersColl.get(chapterIndex));
            data.setIndexOfChapter(chapterIndex);
            data.setIndexOfPage(pageIndex);

            webView.setData(data);
            return pageView;
        }
        return oldPage;
    }

    @Override
    public PageView getNextView(PageView oldPage) 
    {
        MyWebView oldWebView = ((PageView)oldPage).getWebView();
        int chapterIndex = oldWebView.getData().getIndexOfChapter();
        int pageIndex = oldWebView.getData().getIndexOfPage();
        int pageCount = oldWebView.getData().getChapterVO().getPageCount();
        pageIndex++;
        if(pageIndex>=pageCount)
        {
            pageIndex=0;
            chapterIndex++;
            if(chapterIndex>=_chaptersColl.size())
            {
                //end of the chapters and pages so return the same page
                chapterIndex--;
                return null;
            }
            else
            {
                //next chapter first page
                PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                MyWebView webView= pageView.getWebView();

                PageVO data = new PageVO();
                data.setChapterVO(_chaptersColl.get(chapterIndex));
                data.setIndexOfChapter(chapterIndex);
                data.setIndexOfPage(pageIndex);

                webView.setData(data);

                return pageView;
            }
        }
        else
        {
            //next page in same chapter
            PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
            MyWebView webView= pageView.getWebView();

            PageVO data = new PageVO();
            data.setChapterVO(_chaptersColl.get(chapterIndex));
            data.setIndexOfChapter(chapterIndex);
            data.setIndexOfPage(pageIndex);
            //data.setPageCount(pageCount);

            webView.setData(data);

            return pageView;
        }
    }

无需使用任何第三方库。只需花费大量时间编写自己的所有内容即可。

I have developed a native epub player for android and ios

Code I shared here is part of my product source code, copying and pasting of it will not work for you. Consider it as reference.

I have used webview in android and uiwebview in ios making custom view and parsing html/css is almost like developing a new rendering engine (i.e browser).Its a tedious and complex.

Briefly I give you the steps I have followed for android

  • Create a custom webview
  • load url and write call back clients (WebViewClient,WebChromeClient)
  • after webview load do pagination using below method

Code:

private class MyWebClient extends WebViewClient
    {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }
        @Override
        public void onPageFinished(WebView view, String url) 
        {
            super.onPageFinished(view, url);

            final MyWebView myWebView = (MyWebView) view;

            String varMySheet = "var mySheet = document.styleSheets[0];";

                String addCSSRule = "function addCSSRule(selector, newRule) {"
                        + "ruleIndex = mySheet.cssRules.length;"
                        + "mySheet.insertRule(selector + '{' + newRule + ';}', ruleIndex);"

                        + "}";

                String insertRule1 = "addCSSRule('html', 'padding: 0px; height: "
                        + (myWebView.getMeasuredHeight()/getContext().getResources().getDisplayMetrics().density )
                        + "px; -webkit-column-gap: 0px; -webkit-column-width: "
                        + myWebView.getMeasuredWidth() + "px;')";

                myWebView.loadUrl("javascript:" + varMySheet);
                myWebView.loadUrl("javascript:" + addCSSRule);
                myWebView.loadUrl("javascript:" + insertRule1);



        }
    }

private class MyWebChromeClient extends WebChromeClient
    {
        @Override
        public void onProgressChanged(WebView view, int newProgress) 
        {
            super.onProgressChanged(view, newProgress);
            //  GlobalConstants.ENABLE_WEB_VIEW_TOUCH = false;
            if(newProgress == 100)
            {
                postDelayed(new Runnable() 
                {
                    @Override
                    public void run() 
                    {
                        calculateNoOfPages();

                    }
                },300);
            }
        }
    }

private void calculateNoOfPages()
    {

        if(getMeasuredWidth() != 0)
        {
            int newPageCount = computeHorizontalScrollRange()/getMeasuredWidth();
        }
    }

Inject jquery.js into webview:

private void addJQueryJS() 
    {
        String path = "file:///android_asset/JSLibraries/jquery.min.js";
        String data = "{\"MethodName\":\"onJQueryJSLoaded\",\"MethodArguments\":{}}";
        String callBackToNative  = " jsInterface.callNativeMethod('jstoobjc:"+data+"');";
        String script = "function includeJSFile()"
                               +"{"
                               +"function loadScript(url, callback)"
                               +"{"
                               +"var script = document.createElement('script');"
                               +"script.type = 'text/javascript';"
                               +"script.onload = function () {"
                               +"callback();"
                               +"};"
                               +"script.src = url;"
                               +"if(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])"
                               +"{"
                               +"(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);"
                               +"}"
                               +"else { callback(); }"
                               +"}"
                               +"loadScript('"+path+"', function ()"
                               +"{"
                               +callBackToNative
                               +"});"
                               +"} ; includeJSFile();";
        loadUrl("javascript: "+script);
    }
  • wrap all words into spans - used for highlighting text and navigating to a page.
  • there would be 3 webviews - current page ,next page and previous page.You should set offset to webview scroll according to page count of that chapter.
    lets say one .html file has content of 3 pages - previous webview is first page,current webview is second page,next webview is third page but all webviews loaded the same url.But their content offset is different.
  • write you own page swiping logic instead of using viewpager.Just pass the current page to the adapter then adapter will return you the next page and previous page.by some calculations.

Code:

@Override
    public PageView getPreviousView(PageView oldPage) 
    {
        MyWebView oldWebView = ((PageView)oldPage).getWebView();

        int chapterIndex = oldWebView.getData().getIndexOfChapter();
        int pageIndex = oldWebView.getData().getIndexOfPage();
        int pageCount = oldWebView.getData().getChapterVO().getPageCount();
        pageIndex--;
        if(pageIndex < 0)
        {
            pageIndex = 0;
            chapterIndex--;
            if(chapterIndex<0)
            {
                //return the same page
                chapterIndex = 0;
                return null;
            }
            else
            {
                //previous chapter last page
                PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                MyWebView webView= pageView.getWebView();

                PageVO data = new PageVO();
                data.setChapterVO(_chaptersColl.get(chapterIndex));
                data.setIndexOfChapter(chapterIndex);
                data.setIndexOfPage(-2);

                webView.setData(data);
                return pageView;
            }
        }
        else if(pageIndex <= pageCount-1)
        {
            //same chapter previous page
            PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
            MyWebView webView= pageView.getWebView();

            PageVO data = new PageVO();
            data.setChapterVO(_chaptersColl.get(chapterIndex));
            data.setIndexOfChapter(chapterIndex);
            data.setIndexOfPage(pageIndex);

            webView.setData(data);
            return pageView;
        }
        return oldPage;
    }

    @Override
    public PageView getNextView(PageView oldPage) 
    {
        MyWebView oldWebView = ((PageView)oldPage).getWebView();
        int chapterIndex = oldWebView.getData().getIndexOfChapter();
        int pageIndex = oldWebView.getData().getIndexOfPage();
        int pageCount = oldWebView.getData().getChapterVO().getPageCount();
        pageIndex++;
        if(pageIndex>=pageCount)
        {
            pageIndex=0;
            chapterIndex++;
            if(chapterIndex>=_chaptersColl.size())
            {
                //end of the chapters and pages so return the same page
                chapterIndex--;
                return null;
            }
            else
            {
                //next chapter first page
                PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                MyWebView webView= pageView.getWebView();

                PageVO data = new PageVO();
                data.setChapterVO(_chaptersColl.get(chapterIndex));
                data.setIndexOfChapter(chapterIndex);
                data.setIndexOfPage(pageIndex);

                webView.setData(data);

                return pageView;
            }
        }
        else
        {
            //next page in same chapter
            PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
            MyWebView webView= pageView.getWebView();

            PageVO data = new PageVO();
            data.setChapterVO(_chaptersColl.get(chapterIndex));
            data.setIndexOfChapter(chapterIndex);
            data.setIndexOfPage(pageIndex);
            //data.setPageCount(pageCount);

            webView.setData(data);

            return pageView;
        }
    }

No need to use any third party libs .Just need to spend good amount of time to write every thing your own.

〆凄凉。 2024-12-28 08:48:48

不错,但有问题......:-)

我认为 android webview 没有任何分页逻辑可用,根据您的关注,WebView 是显示 .epub 文件的不错选择(您可以添加许多功能,例如,突出显示、搜索、书签等..)。如果您发现了这一点,那么如果设备尺寸发生变化怎么办?我所做的是,我只是在 webview 中显示网页并禁用滚动,然后我可以找到 webview 的最大高度和设备屏幕尺寸(高度和宽度),现在我为下一页和上一页放置了两个按钮,这只是根据设备尺寸的高度滚动页面..

简单的事情..如果你想尝试这个...(这是我个人的观点,可能我在这方面是错的)

Nice One, But in Question... :-)

I don't think any Page Break logic for android webview is available, As per your concern WebView is the good choice to display .epub file (You can add many functionality like, highlight, search, bookmark etc..). And If you found that one then what about if device size is changed. What I am doing is, I just display WebPage in webview and disable scroll, Then I can find the max height of webview, and device screen size (Height and width), Now I have put two buttons for next and previous pages, which just scroll page according to height of device size..

Something easy.. Try this if you want to... (This is my personal opinion may be I am wrong on this)

妥活 2024-12-28 08:48:48

有一个 javascript 库可以解决分页问题

http://monocle.inventivelabs.com.au/

这个项目在android中使用它

https://github.com/sharathpuranik/chaek-android

获取源代码并查看一下。

There's this javascript library that takes care of the pagination issue

http://monocle.inventivelabs.com.au/

This project uses it in android

https://github.com/sharathpuranik/chaek-android

Grab the sourcecode and take a look.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文