Slf4j-android :
http://www.slf4j.org/android/
epublib-core-latest.jar :
https://github.com/downloads/psiegman/epublib/epublib-core-latest.jar (如果不能下载,试试这里)
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 的这个文件和相应工具类就不在列出了,可以到下面的 “源码下载” 中去下载。
参考博客:
这篇文章写不错:
使用epublib解析epub文件(章节内容、书籍菜单)
epublib git地址:
https://github.com/psiegman/epublib
官方网站:
http://www.siegmann.nl/epublib
下面的这两个还没有做了解,先放到这里吧:
epublib解析
epub3reader