Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

render the epub book in android?

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.

like image 287
David Guo Avatar asked Dec 15 '11 10:12

David Guo


2 Answers

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.

like image 170
Uday Sravan K Avatar answered Oct 13 '22 03:10

Uday Sravan K


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)

like image 43
user370305 Avatar answered Oct 13 '22 02:10

user370305