Search code examples
phpandroidretrofitretrofit2fpdf

How to send a specific parameter for PDF generation using FPDF and Retrofit library and download it into Android


I want to send the variable parameter key from Android to FPDF variable in API Server which will generate a set of report based on date range, but the variable in FPDF API wasn't receiving the Android's variable sent.
How to do this? Which Call<> should I use?

I already tried to use Call<ResponseBody> in order to sent the parameter. I am also tried to test it if the connection to the targeted file is success below onResponse and it response true.
But, when the time come for downloading the file into the device I tried to target the download link straightly to the file path in the server.
But after opening the downloaded file what I get is a blank data table which explain that the variable in the FPDF didn't receive the Android variable sent.

Here are my downloadPDF() method, to send the parameter to FPDF API:

private void downloadPDF() {
        RestApi api = RetroFit.getInstanceRetrofit();
        Call<ResponseBody> printCall = api.getPrint(
                strDateFrom,
                strDateTo
        );
        printCall.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                downloadManager();
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Toast.makeText(getContext(), "No data :(", Toast.LENGTH_SHORT).show();
            }
        });
    }

Interface method:

    @FormUrlEncoded
    @POST("somepath/get_print.php")
    Call<ResponseBody> getPrint(
            @Field("keyDateFrom") String from,
            @Field("keyDateTo") String to
    );

downloadManager() method:

private void downloadManager() {
        DownloadManager downloadService = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
        Uri uri = Uri.parse("http://someweb.com/somefolder/get_print.php");
        DownloadManager.Request request = new DownloadManager.Request(uri);
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    }

And my get_print.php script:

<?php

include 'config.php';

$keyDateFrom = $_POST["keyDateFrom"];

$keyDateTo = $_POST["keyDateTo"];

require('fpdf.php');
$pdf = new FPDF('P','mm','A4');
$pdf->AddPage();

$pdf->Image('logo_hsp_transparan.png',10,10,30,15);

$pdf->SetLeftMargin(20);
$pdf->SetFont('Arial','B',16);
$pdf->Cell(190,7,'Daftar Peminjaman Kendaraan HSPnet',0,1,'C');
$pdf->SetFont('Arial','B',9);
$pdf->Cell(190,7,'Jl. Tanah Merdeka No.1, RT.10/RW.3, Rambutan, Ciracas, Kota Jakarta Timur',0,1,'C');
$pdf->Cell(10,7,'',0,1);

$pdf->SetFont('Arial','B',9);
$pdf->Cell(190,7, $keyDateFrom ,0,1,'C');
$pdf->SetFont('Arial','',9);
$pdf->Cell(190,7,'to',0,1,'C');
$pdf->SetFont('Arial','B',9);
$pdf->Cell(190,7, $keyDateTo ,0,1,'C');

$pdf->SetLeftMargin(32);
$pdf->SetFont('Arial','B',8);
$pdf->Cell(10,7,'',0,1,'C');
$pdf->Cell(6,6,'NO',1,0,'C');
$pdf->Cell(35,6,'TUJUAN',1,0,'C');
$pdf->Cell(23,6,'PEMINJAM',1,0,'C');
$pdf->Cell(35,6,'KENDARAAN',1,0,'C');
$pdf->Cell(28,6,'JAM BERANGKAT',1,0,'C');
$pdf->Cell(28,6,'JAM PULANG',1,1,'C');

$pdf->SetFont('Arial','',8);

$query = mysqli_query($link,
"SELECT some_column
FROM `SOME_TABLE`
WHERE (DATE(some_column) BETWEEN '$keyDateFrom' AND '$keyDateTo')");

$i = 1;
while ($row = mysqli_fetch_array($query)){
    $pdf->Cell(6,6,$i++,1,0,'C');
    $pdf->Cell(35,6,$row['some_column'],1,0);
}
$pdf->Output();
?>

I mean, how to make the variable in FPDF API receiving the value from Android, so Android can download the generated file according to the query?
I already tried to do this on Postman it returns a right formatted PDF, but not in Android.

How to do it? What's the alternate? Appreciate any helps.


Solution

  • I am succeeded to retrieve the PDF file from the endpoint PDF table generated which is using 2 variable sent from Android as expected.

    I am using these method as a request

    downloadPDF()

        private void downloadPDF() {
            RestApi api = RetroFit.getInstanceRetrofit();
            Call<ResponseBody> printCall = api.getPrint(
                    strDateFrom,
                    strDateTo
            );
            printCall.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    
                    if (response.isSuccessful()) {
                        Toast.makeText(getContext(), "server contacted and has file", Toast.LENGTH_SHORT).show();
    
                        // The most important part is in below code
                        boolean writtenToDisk = writeResponseBodyToDisk(response.body());
                        Toast.makeText(getContext(), "file download was a success? " + writtenToDisk, Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(getContext(), "Server contact failed ", Toast.LENGTH_SHORT).show();
                    }
    
                }
    
                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    Toast.makeText(getContext(), "No connection", Toast.LENGTH_SHORT).show();
                }
            });
    

    Interface method:

        @FormUrlEncoded
        @POST("somepath/your_file.php")
        Call<ResponseBody> getPrint(
                @Field("keyDateFrom") String from,
                @Field("keyDateTo") String to
        );
    

    And the writeResponseBodyToDisk(ResponseBody body) to write the response into the PDF + saving it into the device

    private boolean writeResponseBodyToDisk(ResponseBody body) {
            try {
                File futureStudioIconFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
                        "yourFileName.pdf");
    
                InputStream inputStream = null;
                OutputStream outputStream = null;
    
                try {
                    byte[] fileReader = new byte[4096];
    
                    long fileSize = body.contentLength();
                    long fileSizeDownloaded = 0;
    
                    inputStream = body.byteStream();
                    outputStream = new FileOutputStream(futureStudioIconFile);
    
                    while (true) {
                        int read = inputStream.read(fileReader);
    
                        if (read == -1) {
                            break;
                        }
    
                        outputStream.write(fileReader, 0, read);
    
                        fileSizeDownloaded += read;
    
                        Log.d("TAG", "file download: " + fileSizeDownloaded + " of " + fileSize);
                    }
    
                    outputStream.flush();
    
                    return true;
                } catch (IOException e) {
                    return false;
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }
    
                    if (outputStream != null) {
                        outputStream.close();
                    }
                }
            } catch (IOException e) {
                return false;
            }
        }
    

    Hopes my confusion helps someone outhere :P