Hello Dear Friends,
My this post is based on "How to Integrate printer in android app". the best way of doing that Google cloud printing. Google provide us Print Dialog code, we can use it in our application. Important steps are given below-
1)Login with your gmail-id in chrome on your desktop and add your printers in your browser.
2)Create a demo app and put below code.
3)Add Internet permissions and read storage.
2)PrintDialogActivity.java
My this post is based on "How to Integrate printer in android app". the best way of doing that Google cloud printing. Google provide us Print Dialog code, we can use it in our application. Important steps are given below-
1)Login with your gmail-id in chrome on your desktop and add your printers in your browser.
2)Create a demo app and put below code.
3)Add Internet permissions and read storage.
<uses-permission android:name="android.permission.INTERNET"
/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"
/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"
/>
1)MainActivity.java
package
com.manish.googleprintdemo;
import java.io.File;
import
android.app.Activity;
import
android.content.Context;
import
android.content.Intent;
import
android.net.ConnectivityManager;
import
android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import
android.os.Environment;
import android.util.Log;
import android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.Toast;
/**
*
* @author manish
*
*/
public class MainActivity extends Activity {
Button
btnPrint;
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPrint=(Button)findViewById(R.id.button1);
btnPrint.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated
method stub
if (isNetworkAvailable() == false) {
Toast.makeText(MainActivity.this,
"Network
connection not available, Please try later",
Toast.LENGTH_SHORT).show();
}
else {
File
file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/personal/xyz.pdf");
Intent
printIntent = new Intent(MainActivity.this, PrintDialogActivity.class);
printIntent.setDataAndType(Uri.fromFile(file),
"application/pdf");
printIntent.putExtra("title", "Android print
demo");
startActivity(printIntent);
}
}
});
}
public boolean isNetworkAvailable()
{
ConnectivityManager
cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo
networkInfo = cm.getActiveNetworkInfo();
// if no network is
available networkInfo will be null
// otherwise check
if we are connected
if (networkInfo != null &&
networkInfo.isConnected()) {
Log.e("Network
Testing", "***Available***");
return true;
}
Log.e("Network
Testing", "***Not Available***");
return false;
}
}
package
com.manish.googleprintdemo;
import
android.annotation.SuppressLint;
import
android.app.Activity;
import
android.content.ActivityNotFoundException;
import
android.content.ContentResolver;
import
android.content.Intent;
import android.os.Bundle;
import android.util.Base64;
import
android.webkit.WebSettings;
import
android.webkit.WebView;
import
android.webkit.WebViewClient;
import
java.io.ByteArrayOutputStream;
import
java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class PrintDialogActivity extends Activity {
private static final String PRINT_DIALOG_URL = "https://www.google.com/cloudprint/dialog.html";
private static final String JS_INTERFACE = "AndroidPrintDialog";
private static final String CONTENT_TRANSFER_ENCODING = "base64";
private static final String ZXING_URL = "http://zxing.appspot.com";
private static final int ZXING_SCAN_REQUEST = 65743;
/**
* Post message that is sent by Print Dialog web page when the printing
dialog
* needs to be closed.
*/
private static final String CLOSE_POST_MESSAGE_NAME = "cp-dialog-on-close";
/**
* Web view element to show the printing dialog in.
*/
private WebView dialogWebView;
/**
* Intent that started the action.
*/
Intent cloudPrintIntent;
@SuppressLint("JavascriptInterface") @Override
public void onCreate(Bundle
icicle) {
super.onCreate(icicle);
setContentView(R.layout.print_dialog);
dialogWebView = (WebView)
findViewById(R.id.webview);
cloudPrintIntent = this.getIntent();
WebSettings settings = dialogWebView.getSettings();
settings.setJavaScriptEnabled(true);
dialogWebView.setWebViewClient(new
PrintDialogWebClient());
dialogWebView.addJavascriptInterface(
new PrintDialogJavaScriptInterface(),
JS_INTERFACE);
dialogWebView.loadUrl(PRINT_DIALOG_URL);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent
intent) {
if (requestCode == ZXING_SCAN_REQUEST &&
resultCode == RESULT_OK) {
dialogWebView.loadUrl(intent.getStringExtra("SCAN_RESULT"));
}
}
final class
PrintDialogJavaScriptInterface {
public String getType() {
return cloudPrintIntent.getType();
}
public String getTitle() {
return cloudPrintIntent.getExtras().getString("title");
}
public String getContent()
{
try {
ContentResolver contentResolver = getContentResolver();
InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = is.read(buffer);
while (n >= 0) {
baos.write(buffer, 0, n);
n = is.read(buffer);
}
is.close();
baos.flush();
return Base64.encodeToString(baos.toByteArray(),
Base64.DEFAULT);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
public String getEncoding()
{
return CONTENT_TRANSFER_ENCODING;
}
public void onPostMessage(String
message) {
if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
finish();
}
}
}
private final class PrintDialogWebClient
extends WebViewClient {
@Override
public boolean
shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(ZXING_URL)) {
Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
intentScan.putExtra("SCAN_MODE", "QR_CODE_MODE");
try {
startActivityForResult(intentScan, ZXING_SCAN_REQUEST);
} catch (ActivityNotFoundException error) {
view.loadUrl(url);
}
} else {
view.loadUrl(url);
}
return false;
}
@Override
public void
onPageFinished(WebView view, String url) {
if (PRINT_DIALOG_URL.equals(url)) {
//
Submit print document.
view.loadUrl("javascript:printDialog.setPrintDocument(printDialog.createPrintDocument("
+ "window." + JS_INTERFACE + ".getType(),window." + JS_INTERFACE + ".getTitle(),"
+ "window." + JS_INTERFACE + ".getContent(),window." + JS_INTERFACE + ".getEncoding()))");
//
Add post messages listener.
view.loadUrl("javascript:window.addEventListener('message',"
+ "function(evt){window." + JS_INTERFACE + ".onPostMessage(evt.data)},
false)");
}
}
}
}
3)activity_main.xml
<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"
tools:context=".MainActivity" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Print" />
</RelativeLayout>
4)print_dialog.xml
<?xml version="1.0"
encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<WebView
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
5)AndroidManifest.xml
<?xml version="1.0"
encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.manish.googleprintdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET"
/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"
/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"
/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.manish.googleprintdemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<activity android:name=".PrintDialogActivity"
/>
</application>
</manifest>
Thanks!
This is awesome. I learnt a lot from your blogs. hope all will learn. Thanks for posting this.
ReplyDeleteYour welcome Gaurav.
Deletegreat work!
ReplyDeleteHey manish, I tried using your code, but everytime I try to print a document, it says "Document missing". There is no error in my address, I have checked repeatedly. Instead of using Environment.getExternalStorageDirectory().getAbsolutePath() + "/personal/xyz.pdf", i have hard - coded the path. Can you please help me?
ReplyDeleteHi Nancy, I think some thing wrong in your path because it is working code as you can see log screen shot. well let me suggest some thing-
Delete1)are you try to print pdf file?
2)file is inside your sdcard or in phone memory? if in sdcard please move to phone memory.
And can you print your file path log and error please? So I can suggest right way..
Thanks
Hey Manish, I wanted to print a pdf stored in some URL, since this option seemed to be the best for the app I'm making, any suggestions on how to print a pdf stored online ?
DeleteThanks a lot!
Hi Manish Srivastava, Thank you for sharing. I have a question: Are there other way to print by wifi in android?
ReplyDeleteHi Luan,
DeleteAs this needs an internet connection, it depends at end user whether it is SIM Card internet or a wi-fi.internet. So I don't think wi-fi matters. Yes it matters if we want an internet connection. At code perspective, I don't think so. I hope you understand now.
And If you're talking about printing through wi-fi printer, you'll have to follow some steps, like scan the wi-fi device , then make a connection, and then make a request for printing. Below are some link that may help you:
Deletehttp://stackoverflow.com/questions/11344572/how-to-send-a-file-from-android-to-wifi-printer-programatically-and-print-the-fi
http://stackoverflow.com/questions/7145787/bluetooth-printer-issue-in-android
Thanks you!
DeleteThanks Manish.....Great work
ReplyDeleteyour welcome Yamini!
Deletehi Manish,
ReplyDeletei have added a classic Epson printer to Google drive and ur code is running as well and give the message print job added.
But problem is I have'nt get print from printer.
could u suggest me?
My email-nishantgupta1205@gmail.com
ph no:+919810680536
follow below steps hope it will help you-
Delete1) login with gmail account in your desktop google chrome ans use same gmail account in your mobile device for printing.
2)go to setting option in your chrome and from there add cloud printer which one attached to your desktop.
3)now print from mobile device it will show you all attached printer list and choose one from them.
Thanks,
Hello Manish,
ReplyDeletei have done these steps already. Problem is my file sometimes added in print jobs with error sign.
have u any idea?
I think you are getting data==null because of big size of attachment or any other reason. Please test on any other device is it working fine or same issue you are facing?
DeleteHi Manish,
ReplyDeleteDo you know how to print data by using USB hosting?. If you know please post that too.
Dear Manish, I wanted to ask you a few questions about your kind posts above for Goolge Cloud Print. I am using Android "Persistent Storage" rather than doing File/IO using Local Data Storage (which appears to be how you have created that PDF file that you are printing in your demo above). I have not studied your code above too much, but right away I realized that my approach is a bit different (since I am using an ArrayList of Notes that are simply TextView String Items). What I want to kindly ask you is... in my case, when my user presses and holds a ListView item (a note item)...I present a Context Menu with some options they can perform. I would like to use that same context menu to add a feature called "Google Cloud Print" and have that Context Menu trigger something similar to what you are doing above. But as I say, I am not loading any PDF files or anything like that... all my data is already loaded from Persistent Storage, and I simply want to dynamically print that note item that the user has selected from my custom ListView Adapter. How can I utitlize your sample code above, for my own project ? What has to change ? And also, do I still need to use ALL of those Manifest Permissions ? You have four of them. two of them I am certainly not sure I still need (since I use Persisnte Storage) are: [android.permission.READ_EXTERNAL_STORAGE] and the other one which is related called: [android.permission.READ_INTERNAL_STORAGE]. I am also not too sure about whether I need the other two permissions you have as well ... the (android.permission.INTERNET) and the (android.permission.ACCESS_NETWORK_STATE)
ReplyDeleteAnyhow...please give me some guidance on how best (easily) to adapt your sample codes above, to make them work in my own application which is utitlizing "persistent storage" and ListView custom adapter to allow user to select their notes from a list, and be able to print them.
Ps. Manish, I tried to also ask about this on a "Hangout" on Google+ community. I am new to Google + as I am to this androidHub forum so please excuse anything from my posts that seem a bit strange, long or out of place. I just wanted to be clear as to where I am with my own Android Project and how best you can help me. I also did not know that Google+ "Hangout" posts are limited by the number of characters you can post. So thats why I came here and decided to elaborate on my own issue.
Thanks so much for your immediate and kind reply to this.
Sincerely yours,
Alexander
Hello Manish,
ReplyDeleteI tried to implement your code into my project...and did all the necessary debugging to get most (if not all the bugs out). To try and implement your code...i show below (all the following changes I had to make).... and now when I try to use the context menu option to Print out a note item to my Printer, nothing happens. I am not getting any errors, but Nothing happens and nothing is printed on my printer whatsoever). I am testing this on a Samsung Galaxy Note 3 --Android Kitkat operating system.
Please keep in mind that I have already registered my HP LaserJet P2035n printer with Google Cloud Print (on my Google + account using the Chrome Browser --successfully. In fact, when I go to a different Note Taking application that you may have heard of called "S Note... I am able to use the "Print" option on a Note from that application, and I am able to Print the item just fine. So I seem to have setup my Printer as well as my Android Smartphone device, to utitlize Google Cloud Print successfuly, as I am able to print a S Note item. However, using your code, nothing is printing and I need to figure out why. Here is what I have done in my own application thusfar.
1) In my public boolean onContextItemSelected(MenuItem item) , I have created a new Context menu item and check for when it is selected when the user is pressing on a Note Item in my custom ListView. Here is what the code looks like:
if (item.getItemId() == MENU_CLOUD_PRINT_ID) //if user selected to Cloud Print their note, we handle that
{
NoteItem note = notesList.get(currentNoteId); //grab the NoteItem that was selected from list
String message = note.getText(); //get the message of the note that we wish to print
if (isNetworkAvailable() == false) {
Toast.makeText(MainActivity.this,
"Network connection not available, Please try later",
Toast.LENGTH_SHORT).show();}
else
{
Intent printIntent = new Intent (MainActivity.this, PrintDialogActivity.class);
printIntent.putExtra("title", message); // pass the message the user slected , to Print activity
}
}
2) I have created my PrintDialogActivity.java exactly as you have prescribed. I have also bound that activity to the print_dialog.xml layout file as you suggest. Which means my print_dialog.xml file is also exactly setup like yours.
The only thing I did not do (*since I dont think I need to in my case*) was to creaet a "Print" button inside my activity_main.xml ..... the reason is because I am using a context menu to allow the user to initiate the print job. And you are using a button.
So please tell me why Nothing is printing out on my printer ? I am totally lost.
Thanks
Dear Manish,
ReplyDeleteAfter some more careful analysis of my code, I realized that in my intent call from my MainActivity.java, I was misssing some critical lines that you actually HAD , in your else clause. Let me show you what my current else clause looks like.
else
{
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/personal/xyz.pdf");
Intent printIntent = new Intent (MainActivity.this, PrintDialogActivity.class);
printIntent.setDataAndType(Uri.fromFile(file), "application/pdf");
printIntent.putExtra("title", message);
startActivity(printIntent);
}// end of else clause
My problem now is that my Activity Crashes when I run my code. As soon as I add the lines of:
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/personal/xyz.pdf");
printIntent.setDataAndType(Uri.fromFile(file), "application/pdf");
and started my activity, with:
startActivity(printIntent);
Now my MainActivity.java crashes. I have a feeling its because this PDF file (xyz.pdf)
at the path == > /personal/xyz.pdf DOES NOT EXIST
Can you please tell me how I can adapt your code to work with a case like MINE where I AM NOT reading any PDF file that I wish to print. In my case, as I stated earlier, I am allowing the user to Select a ListView Note Item from a LIST and I display a Conext Menu with an option allowing them to HOPEFULLY be able to Print their Note to their Cloud Printer (which has already been setup presumably ahead of time by that user). I dont want my Application to be responsible for helping them setup (configure) their cloud printer (as far as registering it with their Google + account in Chrome -- meaning finding it on their network and setting it in their Google + account for Cloud Printing). I also dont want to be responsible for them downloading and setting up the Google Cloud Print (free app from market place). I ONLY WANT that they should be able to do a print.
So given that I dont have a file xyz.pdf (which is not created by my app and is not existing)... How do I modify your code to make it work in my situation ?
Please reply ASAP.
Thanks
Alexander
Hey friend, thanks for your onwer. And i am sorry this time your problem seems big and i have tight dead line so i cant able to look on it..
DeleteHey friend, thanks for your onwer. And i am sorry this time your problem seems big and i have tight dead line so i cant able to look on it..
DeleteHello Manish. Thanks for the kind and honest reply. Actually, my challenge is not that complicated if I explain to you my question in another way. Suppose you have a String stored in a variable called "statement" - - which may be a statement about let's say the cruelty of killing elephants for their tusks. Now, let's say you want to print this statement. How can you achieve (hopefully without the requirement to first create an external PDF file out of the statement, then storing it to disk, and the reloading it and passing it into your PrintDialogActivity.class
DeleteI mean Manish, should there not be some simple way to print a string to a printer directly (without resorting to fancy File/IO requirements?)
This is my real question from anyone who can help me please.
Thank you all very much.
I can understand what you are trying to print. But as per my knowledge you need a file at-least in any format HTML, PDF, DOC any but you need. In android there are only two type of printing option-
Delete1) Wireless Bluetooth printing
2)Using cloud printer what I am doing.
But in both case you need a file like you have a listview nd want to print it so you need to write this data into a file then only you can print.
Well why you are thinking like that? Make it at your end user will not know about your internal code. After print the file just remove that from disc.
Just forget android for a minute and let me know can you print a variable in java or in any language using desktop when there a printer attach with your desktop? You need to print an object, file etc..
Please don't mind try over the world and do Google there are some chargeable library and they have own printing machine, might be they help you. Well if you got anything please let me know I am interested to know.
Thank you!
Since you're writing to the file system you also need to add .
ReplyDeleteWhen using Android 4.4 you do not need to use above code to print, you can also use android.print
Also add following permission to the manifest: android.permission.WRITE_EXTERNAL_STORAGE
ReplyDeleteThank Guy!
DeleteHi manish,
ReplyDeleteUr code works like charm.
I have a doubt that can i just print a file from my external storage ?
Is this possible to print the webview content form android without opening the printer popup
ReplyDeleteHi Manish.. Thanks for this tutorial. I am developing a android application. I have completed all the functions. But Now I want to generate a bill as pdf and print it. Can you suggest me any printer for bill printing and can you give me any samples for pdf generator.
ReplyDeleteThanks and Regards
C. Vijayadhas
vijaydhascr@gmail.com
Hi Manish,
ReplyDeleteI need to print images, how to print images I have the path.
when i click on my print i have this error:
ReplyDeleteFatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)
Why?
I Guess this is just because of NDK code on Emulator or NEXUS device. May I know which device phone you are using? And your chrome have global login and attached to a printer?
DeleteDear Manish, Thanks in advance for your help, I have one question mate, for using Clous Printer, the android device and the printer have to be conected in the the same network. or Can I use my android device from an external network?
ReplyDeleteThanks mate
You must login into google chrome through your laptop or desktop and printer should be attached to your laptop. Then using same google chrome login from anywhere you can access cloud printer from your android phone. Same network is not required.
DeleteHi Manish, I am trying to print a pdf stored in the internal memory, but when appear the popup of cloud print, don´t appear the pdf, i am sure that the patch is right, can you help me?
ReplyDeleteThanks friend
Off-course you can print a pdf file, please debug your code there should be miner mistake. I can't suggest anything without code.
Deletehi, thanks for the code, it's awesome.
ReplyDeletei got 1 more question. how can i use the android to connect the printer by TCP/IP?
Hi manish!!
ReplyDeleteGreat work bro !! But i want to integrate my android app with google cloud print without the webview !! can i ??? Please Help