android 使用epublib開源框架解析epub檔案(章節內容、書籍選單)
阿新 • • 發佈:2019-02-20
前期準備
jsoup(可以可把html標籤,解析為物件):
進入正題
如果你是吧 .equb 格式的檔案放到 assets 檔案下,你可以這樣獲取book物件。
MainActivity.java
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app .AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView ;
import com.example.epubdaemon.utils.StringUtils;
import com.example.epubdaemon.utils.TimeUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat ;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.Metadata;
import nl.siegmann.epublib.domain.Resource;
import nl.siegmann.epublib.domain.Spine;
import nl.siegmann.epublib.domain.SpineReference;
import nl.siegmann.epublib.epub.EpubReader;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@BindView(R.id.image)
ImageView mImage;
@BindView(R.id.tv_text)
TextView mTvText;
@BindView(R.id.recycler)
RecyclerView mRecycler;
private Book book;
private MyAdatper mAdatper;
private List<EpubBean> indexTitleList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initView();
}
private void initView() {
mRecycler.setLayoutManager(new LinearLayoutManager(this));
mAdatper = new MyAdatper(indexTitleList, this);
mRecycler.setAdapter(mAdatper);
try {
EpubReader reader = new EpubReader();
InputStream in = getAssets().open("176116.epub");
book = reader.readEpub(in);
//獲取封面圖方法一:
/* Bitmap coverImage = BitmapFactory.decodeStream(book.getCoverImage().getInputStream());
if (coverImage!=null) {
mImageView.setImageBitmap(coverImage);
}else {
Log.i(TAG, "onCreate: mImageView is null");
}*/
// 獲取封面圖方法二:
/*nl.siegmann.epublib.domain.Resources resources = book.getResources();
Resource res = resources.getById("cover");
byte[] data = res.getData();
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
mImage.setImageBitmap(bitmap);*/
Metadata metadata = book.getMetadata();
StringBuffer buffer = new StringBuffer();
for (String s : metadata.getDescriptions()) {
buffer.append(s + " ");
}
/*String bookInfo = "作者:" + metadata.getAuthors() +
"\n出版社:" + metadata.getPublishers() +
"\n出版時間:" + metadata.getDates() +
"\n書名:" + metadata.getTitles() +
"\n簡介:" + metadata.getDescriptions() +
"\n語言:" + metadata.getLanguage() +
"\n\n封面圖:";*/
String bookInfo = "作者:" + metadata.getAuthors().get(0) +
"\n出版社:" + metadata.getPublishers().get(0) +
"\n出版時間:" + TimeUtils.getStringData(metadata.getDates().get(0).getValue()) +
"\n書名:" + metadata.getTitles().get(0) +
"\n簡介:" + metadata.getDescriptions().get(0) +
"\n語言:" + metadata.getLanguage() +
"\n\n封面圖:";
mTvText.setText(bookInfo);
// Log.i(TAG, "onCreate: bookInfo=" + bookInfo);
// 書籍的閱讀順序,是一個線性的順序。通過Spine可以知道應該按照怎樣的章節,順序去閱讀,
// 並且通過Spine可以找到對應章節的內容。
Spine spine = book.getSpine();
List<SpineReference> spineReferences = spine.getSpineReferences();
if (spineReferences != null && spineReferences.size() > 0) {
Resource resource = spineReferences.get(1).getResource();//獲取帶章節資訊的那個html頁面
Log.i(TAG, "initView: ddd=" + resource.getId() + " " + resource.getTitle() + " " + resource.getSize() + " ");
byte[] data = resource.getData();//和 resource.getInputStream() 返回的都是html格式的文章內容,只不過讀取方式不一樣
String strHtml = StringUtils.bytes2Hex(data);
Log.i(TAG, "initView: strHtml= " + strHtml);
parseHtmlData(strHtml);
/* InputStream inputStream = resource.getInputStream();
String strHtml = StringUtils.convertStreamToString(inputStream);
Log.i(TAG, "initView: strHtml=" + strHtml);*/
} else {
Log.i(TAG, "initView: spineReferences is null");
}
// 獲取所有章節內容。測試發現和 spine.getSpineReferences() 效果差不多
/* List<Resource> contents = book.getContents();
if (contents != null && contents.size() > 0) {
try {
Resource resource = contents.get(1);
//byte[] data = resource.getData();
InputStream inputStream = resource.getInputStream();
String dddd = StringUtils.convertStreamToString(inputStream);
Log.i(TAG, "onCreate: dddd=" + dddd);
//mTextView.setText(Html.fromHtml(dddd));
// mWebView.loadDataWithBaseURL(null, dddd, "text/html", "utf-8", null);
} catch (IOException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "onCreate: contents is null");
}*/
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解析html
*/
private void parseHtmlData(String strHtml) throws IOException {
Document doc = Jsoup.parse(strHtml);
Log.i(TAG, "parseHtmlData: doc.title();=" + doc.title());
Elements eles = doc.getElementsByTag("a"); // a標籤
// 遍歷Elements的每個Element
EpubBean epubBean;
for (Element link : eles) {
String linkHref = link.attr("href"); // a標籤的href屬性
String text = link.text();
epubBean = new EpubBean();
epubBean.href = linkHref;
epubBean.tilte = text;
indexTitleList.add(epubBean);
//Log.i(TAG, "parseHtmlData: linkHref=" + linkHref + " text=" + text);
}
}
private class MyAdatper extends RecyclerView.Adapter<MyAdatper.ViewHolder> {
private final LayoutInflater mInflater;
private List<EpubBean> mStrings;
public MyAdatper(List<EpubBean> mStrings, Context context) {
this.mStrings = mStrings;
mInflater = LayoutInflater.from(context);
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView mTextView;
public ViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.title);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.mTextView.setText(mStrings.get(position).tilte);
holder.mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通過href獲取
String href = mStrings.get(position).href;
Intent intent = new Intent(MainActivity.this, ChapterDetailActivity.class);
intent.putExtra("href", href);
startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mStrings.size();
}
}
}
佈局: R.layout.activity_main :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="150dp"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="內容描述dddd"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
adapter的item佈局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#fff"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:text="ddd"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#eee"/>
</LinearLayout>
EpubBean.java
public class EpubBean {
public String tilte;
public String href;
}
ChapterDetailActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.webkit.WebView;
import com.example.epubdaemon.utils.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import butterknife.BindView;
import butterknife.ButterKnife;
import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.Resource;
import nl.siegmann.epublib.epub.EpubReader;
public class ChapterDetailActivity extends AppCompatActivity {
private static final String TAG = "ChapterDetailActivity";
@BindView(R.id.webView)
WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chapter_detail);
ButterKnife.bind(this);
String href = getIntent().getStringExtra("href");
Log.i(TAG, "onCreate: href=" + href);
try {
EpubReader reader = new EpubReader();
InputStream in = getAssets().open("176116.epub");
Book book = reader.readEpub(in);
Resource byHref = book.getResources().getByHref(href);
byte[] data = byHref.getData(); //和 resource.getInputStream() 返回的都是html格式的文章內容,只不過讀取方式不一樣
String strHtml1 = StringUtils.bytes2Hex(data);
//Log.i(TAG, "initView: strHtml1111= " + strHtml1);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadDataWithBaseURL(null, strHtml1, "text/html", "utf-8", null);
} catch (IOException e) {
e.printStackTrace();
}
}
}
佈局:R.layout.activity_chapter_detail
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"></WebView>
</LinearLayout>
StringUtils.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
/**
* Created by yuanpk on 2018/4/26 8:43
* <p>
* Description:TODO
*/
public class StringUtils {
public static String convertStreamToString(InputStream is) {
/*
* To convert the InputStream to String we use the BufferedReader.readLine()
* method. We iterate until the BufferedReader return null which means
* there's no more data to read. Each line will appended to a StringBuilder
* and returned as String.
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
public static String bytes2Hex(byte[] bs) {
if (bs == null || bs.length <= 0) {
return null;
}
Charset charset = Charset.defaultCharset();
ByteBuffer buf = ByteBuffer.wrap(bs);
CharBuffer cBuf = charset.decode(buf);
return cBuf.toString();
}
}
最後,176116.epub 的這個檔案和相應工具類就不在列出了,可以到下面的 “原始碼下載” 中去下載。
原始碼下載
參考部落格: