Cara Membuat Ebook Android dengan AndroidEBookTemplate


Penggunaan buku digital atau ebook mulai menggantikan buku fisik akhir-akhir ini.

Dengan buku digital, biaya produksi sebuah buku bisa ditekan.

Di sisi lain, ebook juga lebih ramah lingkungan karena mengurangi jumlah pohon yang harus ditebang untuk menjadi bahan kertas.

Selain itu, ebook juga lebih mudah didistribusikan.

Dengan cara download, sebuah ebook yang tebalnya ratusan halaman dapat dikirimkan tanpa memikirkan berat buku.

Terdapat berbagai jenis ebook ditinjau dari format filenya.

Salah satu format ebook yang popular adalah PDF.

Dengan format PDF, kita bisa membaca Ebook yang memiliki font yang konsisten di platform manapun ebook tersebut dibaca.

Selain itu masih ada format ebook lain seperti epub yang tidak dibahas di sini.

Selain kedua jenis ebook tadi, masih ada satu jenis ebook lagi.

Jenis itu disebut dengan Android ebook.

Ebook dengan jenis Android ebook ini adalah ebook yang hanya bisa dibaca pada platform Android.

Hanya bisa dibaca di platform tersebut karena kontainer dari ebook tersebut berupa aplikasi Android yang berformat APK.

Karena berupa aplikasi, ebook dari jenis ini harus diinstall dulu ke Android sebelum dapat dibaca.

Kita akan membahas cara membuat jenis ebook ini sekarang.

Sebelumnya, download terlebih dahulu source code project ini:


Seperti Apa Sih Aplikasi Ebook Android yang Akan Kita Buat?

Aplikasi ebook ini memiliki dua fungsi utama.

Fungsi pertama adalah membaca konten langsung di Android device.

Fungsi kedua adalah membaca konten dari browser di PC/Laptop yang ada pada jaringan yang sama dengan Android device tersebut.

Fungsi lainnya adalah tombol untuk men-download source code pendukung untuk ebook yang dibaca, tapi fungsi ini tidak wajib.

Tergantung jenis bukunya.

Jika bukunya bukan buku pemrograman, maka fungsi ini tidak diperlukan.

Bisa kita lihat pada gambar di bawah ini, bahwa terdapat 2 tombol utama untuk fungsi-fungsi yang telah kita bicarakan tadi:



Tombol pertama, yang di bagian atas adalah untuk membaca ebook langsung di Android device.

Tombol kedua, yang dibawah untuk membaca ebook melalui browser di PC/Laptop.

Apabila tombol pertama ditekan, maka pengguna akan diarahkan ke halaman-halaman ebook.

Lebih jelasnya, lihat gambar di bawah ini:




Sedangkan, apabila tombol kedua ditekan, maka akan muncul informasi tentang IP address dan port dimana buku tersebut dapat diakses melalui browser di PC/Laptop.

Lebih jelasnya, lihat gambar di bawah ini:



Dan seperti inilah tampilannya di browser:



Membuat Project Aplikasi Ebook Android

Sebelum kita membuat aplikasi ebook ini, pastikan kita telah meng-install Android Studio.

Untuk menginstall Android Studio, download dari sini:

Selanjutnya, pastikan bahwa kita telah meng-install Android SDK versi 4.0.0 atau API 14.

Kita menggunakan versi tersebut agar ebook yang kita buat dapat digunakan oleh banyak versi Android.

Sekarang, setelah semua itu terinstall, buatlah sebuah folder bernama "AndroidEBookTemplate".

Lokasi folder tersebut bisa di mana saja, tapi carilah tempat yang mudah diakses.

Selanjutnya, buat sebuah project Android Studio. Lebih jelasnya, lihat gambar ini:



Pada layar pertama, isi inputnya sesuai dengan gambar ini:



Sedangkan pada "Project Location", pilih folder "AndroidEBookTemplate" tadi.

Kita tidak memerlukan C++ dan Kotlin support, jadi jangan dicentang.

Pada layar kedua, pastikan kita memilih "Phone and Tablet" dan pilih API 14.


Pada layar ketiga, pilih "Empty Activity":



Pada layar keempat, beri nama "ActivityMain" dan layoutnya bernama "activity_main.xml":


Membuat Asset Folder dan Mengisinya dengan File PDF

Setelah kita membuat project baru, buatlah sebuah asset folder pada project.

Folder ini akan diisi file PDF yang akan ditampilkan pada aplikasi ebook ini.

Caranya adalah dengan klik kanan di tab "Android" di sebelah kiri layar, kemudian New | Folder | Asset Folder.

Setelah itu, sebuah folder bernama "asset" akan dibuat.

Lebih jelasnya, lihat gambar di bawah ini:



Selanjutnya, kita akan mengisi folder tersebut dengan file PDF yang akan ditampilkan.

Untuk itu, dibutuhkan sebuah file PDF apapun.

Pilih file PDF yang Anda inginkan, kemudian rename menjadi "contohpdf.pdf".

Selanjutnya, copy "contohpdf.pdf" ke dalam asset folder.

Meng-Install Library yang Dibutuhkan

Karena aplikasi ebook ini memiliki 2 fungsi utama:

  • Menampilkan file PDF di Android
  • Menampilkan file PDF melalui browser di PC atau Laptop


Maka dibutuhkan 2 library ini:

  • Android PDF Viewer untuk menampilkan file PDF di Android
  • NanoHTTPD untuk membuat server agar file PDF dapat diakses melalui browser PC atau Laptop.


Untuk menginstall kedua library tersebut, buka build.gradle (module:app) dan isi bagian dependencies dengan ini:

compile 'com.github.barteksc:android-pdf-viewer:2.7.0'
compile 'org.nanohttpd:nanohttpd:2.3.0'

Jadi build.gradle (module:app) bagian dependencies-nya sepserti ini:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.github.barteksc:android-pdf-viewer:2.7.0'
    compile 'org.nanohttpd:nanohttpd:2.3.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

Isi build.gradle tadi bisa berbeda-beda tergantung versi Android Studio yang terinstall.

Selajutnya save, kemudian klik "Sync Now" di bagian kanan atas file build.gradle tadi.

Membuat Layout

Karena ada 2 tampilan layar di aplikasi ebook ini, maka kita akan membuat 2 buah layout.

Layout pertama berupa welcome screen di mana pengguna bisa memilih, apakah akan membaca ebook di Android device atau membacanya di PC atau Laptop melalui browser.

Layout kedua berupa PDF view di mana pengguna dapat membaca ebook di Android device.

Pada layout kedua ini juga ada tombol "Download Source Code" yang akan mengarahkan pembaca ke lokasi untuk men-download source code pendukung ebook.

Berikut ini adalah isi dari layout pertama (activity_main.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <Button
        android:id="@+id/btnReadPCLaptop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:text="Baca di PC/Laptop" />

    <Button
        android:id="@+id/btnReadMobileDevice"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/btnReadPCLaptop"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:text="Baca di Mobile Device" />

    <TextView
        android:id="@+id/txvTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:gravity="center_horizontal"
        android:textStyle="bold"
        android:textSize="40dp"
        android:text="Panduan Node.js 8.x dalam 14 Bab" />

    <TextView
        android:id="@+id/txvServerInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/btnReadMobileDevice"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:gravity="center_horizontal"
        android:text="Server tidak berjalan"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/txvMyName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/txvTitle"
        android:layout_centerHorizontal="true"
        android:text="Lusfikar Sheba" />

    <ImageView
        android:id="@+id/imvLogo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:src="@drawable/cover" />

</RelativeLayout>

Berikut ini adalah isi dari layout kedua (activity_read_mobile.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_above="@+id/btnDownloadSC" />

    <Button
        android:id="@+id/btnDownloadSC"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:textStyle="bold"
        android:text="Download Source Code!"/>
</RelativeLayout>

Pada layout kedua ini, terdapat tag:

Tag itu adalah tag custom untuk PDF View yang disediakan oleh library "Android PDF Viewer".

Karena mengandung custom tag, kita tidak bisa melihat preview tampilannya di tab "design".

Akan tetapi setelah aplikasi ebook ini di-build dan dijalankan pada Android device, kita akan mendapati sebuah PDF view di bagian atas, dan sebuah tombol "Download Source Code" di bawahnya.

Menambahkan AndroidManifest.xml

Karena di dalam aplikasi ebook ini terdapat 2 Activity: ActivityMain dan ActivityReadMobile, maka kita perlu mendaftarkan ActivityReadMobile dalam AndroidManifest.xml

Tambahkan kode berikut ini di bawah ActivityMain di file AndroidManifest.xml:

<activity android:name=".ActivityReadMobile">
</activity>

Selanjutnya, kita juga perlu menambahakan uses permission ke dalam AndroidManifest.xml karena kita harus bisa mengakses aplikasi ebook ini dari PC atau Laptop melalui browser.

Tambahkan kode ini setelah tag manifest:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Jadi, sekarang seluruh isi AndroidManifest.xml seperti ini:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="space.lusfikars.androidebooktemplate">
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".ActivityMain">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ActivityReadMobile">
        </activity>
    </application>

</manifest>

Menambahkan Java Class

Langkah selanjutnya adalah membuat Java Class yang dibutuhkan.

Secara umum, aplikasi ebook ini memiliki 4 Java Class:

  • Utils
  • WebBookServer
  • ActivityReadMobile
  • ActivityMain


Utils

Class Utils berisi informasi mengenai nama file PDF dalam folder asset yang akan bisa dibaca oleh pengguna.

Class itu juga berisi URL download source code.

Selain itu, class Utils juga memiliki sebuah method untuk mendapatkan IP address dari Android device yang menjalankan server untuk ebook.

Berikut ini adalah isi dari file Utils.java:

package space.lusfikars.androidebooktemplate;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;

/**
 * Created by laptop.baru.bagus on 1/5/2018.
 */

public class Utils {
    public static String namaBuku = "contohpdf.pdf";
    public static String downloadSCLink = "https://drive.google.com/file/d/1Dn4ufeAL0nxsw-Xjqm2iTj4AozaiP8yp/view?usp=sharing";

    public static String getIPAddress(boolean useIPv4) {
        try {
            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) {
                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
                for (InetAddress addr : addrs) {
                    if (!addr.isLoopbackAddress()) {
                        String sAddr = addr.getHostAddress();
                        //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
                        boolean isIPv4 = sAddr.indexOf(':')<0;

                        if (useIPv4) {
                            if (isIPv4)
                                return sAddr;
                        } else {
                            if (!isIPv4) {
                                int delim = sAddr.indexOf('%'); // drop ip6 zone suffix
                                return delim<0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase();
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) { } // for now eat exceptions
        return "";
    }
}

WebBookServer

Class WebBookServer adalah class yang menangani request dari browser di PC atau Laptop.

Dengan class ini, kita akan merespon request dari PC/Laptop dalam bentuk file PDF.

Berikut ini adalah kode dari WebBookServer.java:

package space.lusfikars.androidebooktemplate;

import android.app.Application;
import android.content.Context;
import android.os.Environment;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.util.Map;
import java.util.logging.Logger;

import fi.iki.elonen.NanoHTTPD;

/**
 * Created by laptop.baru.bagus on 1/5/2018.
 */

public class WebBookServer extends NanoHTTPD {
    private static final Logger LOG = Logger.getLogger(WebBookServer.class.getName());
    Context context;

    public WebBookServer(Context context) throws IOException {
        super(8080);
        this.context = context;
        doStart();
    }

    public WebBookServer(Context context, int port){
        super(port);
        this.context = context;
    }

    public void doStart() throws IOException{
        start();
        WebBookServer.LOG.info( "Web book server is started" );
    }

    public void doStop(){
        stop();
        WebBookServer.LOG.info( "Web book server is stopped.." );
    }

    @Override
    public Response serve(IHTTPSession session) {
        InputStream fis;
        try {
            fis = context.getResources().getAssets().open(Utils.namaBuku);
        } catch (IOException e) {
            e.printStackTrace();
            return newFixedLengthResponse( "ERROR: Cannot open the pdf asset!" );
        }
        return newChunkedResponse(Response.Status.OK, "application/pdf", fis);
    }
}

ActivityReadMobile

Class ActivityReadMobile adalah class yang akan menampilkan activity untuk membaca ebook langsung di Android device.

Class ini mengimplementasikan class a dan b sehingga listenernya bisa digunakan dalam class ini.

Berikut ini adalah kode dari ActivityReadMobile.java:

package space.lusfikars.androidebooktemplate:

package space.lusfikars.androidebooktemplate;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener;
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener;
import com.github.barteksc.pdfviewer.scroll.DefaultScrollHandle;

import java.util.logging.Logger;

/**
 * Created by laptop.baru.bagus on 1/5/2018.
 */

public class ActivityReadMobile extends Activity implements OnPageChangeListener, OnLoadCompleteListener {
    private static final Logger LOG = Logger.getLogger(ActivityReadMobile.class.getName());

    PDFView pdfView;

    Integer pageNumber = 0;

    private Button btnDownloadSC;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read_mobile);

        btnDownloadSC = (Button)findViewById(R.id.btnDownloadSC);

        pdfView = (PDFView)findViewById(R.id.pdfView);
        pdfView.setBackgroundColor(Color.DKGRAY);
        pdfView.fromAsset(Utils.namaBuku)
                .defaultPage(pageNumber)
                .onPageChange(this)
                .enableAnnotationRendering(true)
                .onLoad(this)
                .scrollHandle(new DefaultScrollHandle(this))
                .spacing(10) // in dp
                .load();

        btnDownloadSC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String urlString=Utils.downloadSCLink;
                Intent intent=new Intent(Intent.ACTION_VIEW,Uri.parse(urlString));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setPackage("com.android.chrome");
                try {
                    startActivity(intent);
                } catch (ActivityNotFoundException ex) {
                    // Chrome browser presumably not installed so allow user to choose instead
                    intent.setPackage(null);
                    startActivity(intent);
                }
            }
        });
    }

    @Override
    public void loadComplete(int nbPages) {

    }

    @Override
    public void onPageChanged(int page, int pageCount) {
        pageNumber = page;
    }
}

ActivityMain

Class ActivityMain merupakan activity "Welcome Screen" yang akan memberi navigasi apakah pengguna akan memilih untuk membaca ebook langsung dari Android device atau melalui browser di PC atau Laptop.

Berikut ini adalah kode dari ActivityMain.java:

package space.lusfikars.androidebooktemplate;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.logging.Logger;

public class ActivityMain extends AppCompatActivity {

    private static final Logger LOG = Logger.getLogger(ActivityMain.class.getName());

    private Button btnReadMobile;
    private Button btnReadPCLaptop;
    private TextView txvServerInfo;

    private WebBookServer server;
    int randomPort = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txvServerInfo = (TextView)findViewById(R.id.txvServerInfo);
        btnReadMobile = (Button)findViewById(R.id.btnReadMobileDevice);

        btnReadMobile.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent myIntent = new Intent( getApplicationContext(), ActivityReadMobile.class);
                startActivity(myIntent);
            }
        });

        btnReadPCLaptop = (Button)findViewById(R.id.btnReadPCLaptop);
        btnReadPCLaptop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(btnReadPCLaptop.getText().equals("Baca di PC/Laptop")){

                    randomPort = getRandomPort();
                    if(randomPort == -1){
                        Toast.makeText(getApplicationContext(), "Error: No port available!", Toast.LENGTH_LONG).show();
                        return;
                    }

                    server = new WebBookServer(getApplicationContext(), randomPort);
                    try {
                        server.doStart();
                    } catch (IOException e) {
                        e.printStackTrace();
                        return;
                    }

                    String msg = "Buka PC/Laptop Browser Anda ke: " + "http://" + Utils.getIPAddress(true) + ":" + Integer.toString(randomPort);

                    txvServerInfo.setText(msg);

                    Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

                    btnReadPCLaptop.setText("Berhenti Baca di PC/Laptop");

                } else if(btnReadPCLaptop.getText().equals("Berhenti Baca di PC/Laptop")){

                    if(server != null) {
                        server.doStop();

                        String msg = "Server tidak berjalan";

                        txvServerInfo.setText(msg);

                        Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

                        btnReadPCLaptop.setText("Baca di PC/Laptop");
                    }
                }
            }
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        //Toast.makeText(getApplicationContext(),"onResume", Toast.LENGTH_SHORT).show();
        if(server == null){
            //Toast.makeText(getApplicationContext(),"server is null", Toast.LENGTH_SHORT).show();
            return;
        }

        if(server.isAlive() == true){
            if(btnReadPCLaptop != null && txvServerInfo != null){
                String msg = "Buka PC/Laptop Browser Anda ke: " + "http://" + Utils.getIPAddress(true) + ":" + Integer.toString(randomPort);

                txvServerInfo.setText(msg);

                btnReadPCLaptop.setText("Berhenti Baca di PC/Laptop");
            }
        } else {
            if(btnReadPCLaptop != null && txvServerInfo != null) {
                String msg = "Server tidak berjalan";

                txvServerInfo.setText(msg);

                btnReadPCLaptop.setText("Baca di PC/Laptop");
            }
        }
        //Toast.makeText(getApplicationContext(),"on resume", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //Toast.makeText(getApplicationContext(),"onDestroy", Toast.LENGTH_SHORT).show();

        if(server != null){
            server.doStop();
        }
    }

    private int getRandomPort(){
        //return 8080;

        ServerSocket socket;
        int port = 0;
        try {
            socket = new ServerSocket(0);
            port = socket.getLocalPort();
            socket.close();
        } catch (IOException e) {
            port = -1;
        }
        return port;
    }
}

Perhatikan pada kode bagian ini:

private int getRandomPort(){
 //return 8080;

 ServerSocket socket;
 int port = 0;
 try {
  socket = new ServerSocket(0);
  port = socket.getLocalPort();
  socket.close();
 } catch (IOException e) {
  port = -1;
 }
 return port;
}

Di situ kita mencari port random yang akan digunakan untuk mengakses ebook dari browser.

Untuk itu diperlukan ServerSocket yang diisi dengan nilai 0.

Penutup

Sekarang kita bisa mencoba aplikasi ebook ini melalui emulator.

Sebagai tambahan, apabila kita mencoba mengakses ebook dari browser pc ke emulator, kita perlu menjalankan perintah berikut ini:
adb forward tcp:80 tcp:<nomor_port_ebook>
Hal ini diperlukan agar server ebook bisa diakses melalui localhost:
http://localhost
Apabila kita menggunakan hp Android sungguhan, kita bisa mengetesnya di URL yang diberikan di aplikasi ebook ini.

Sekian.