[Android] GoogleCloudPrint

GoogleCloudPrintをAndroidで簡単にできたのでメモ

GoogleCloudPrintってなんぞ?という方はこちらを参照 => GoogleCloudPrint

今回作る画面は2画面。

≪印刷ボタン画面≫
印刷ボタンを配置している画面です。
今回はボタンだけでファイル指定は固定にしてますが、ここにファイルを指定するプログラムを作れば好きなファイルを印刷できます。

≪印刷画面≫
実際に印刷の設定と印刷を実行させる画面です。
これはWebViewで既に用意されてるものを表示するので特に考える必要はありません。
ソースもほぼ公式のもの(こちらのPrintDialogActivity.java部分)をコピペで問題ないです。(ファイル名もそのまま)
※ただし、一部追加しないと動きません。

————-
印刷ボタン画面

// 印刷するファイルを指定
File file = new File("<ここに参照ディレクトリ>");
// ファイルの有無を確認
if (file.exists()){
	Intent printIntent = new Intent(this, PrintDialogActivity.class);
	printIntent.setDataAndType(Uri.parse("file://"+file.getPath()), "application/pdf");
	printIntent.putExtra("title", "docTitle");
	startActivity(printIntent);
}else{
    Toast.makeText(ctx, "ファイルが存在しません", Toast.LENGTH_SHORT).show();
    finish();
}

上記の公式リンクを見た人はわかると思いますが、こちらもほとんどがそのままです。
公式のものにファイルのURIを追加しただけですねw

重要な部分はここかな

printIntent.setDataAndType(Uri.parse("file://"+file.getPath()), "application/pdf");
printIntent.putExtra("title", "docTitle");

setDataAndTypeには第一引数にURI、第二引数にMIME Typeを指定。
MIME Typeは下記サイト参照(plalaさんお借りします!)
MIME Type 一覧表(plala)
これがすべてではないと思いますのでご注意を。
ちなみに印刷で使うとしたらこの中の10個も使わないと思いますw

putExtraにはJobタイトルを指定します。
印刷Jobを確認するときに判別するためのものなので、できるだけ重複しないものがいいと思います。

————-
印刷画面

・プリントする画面のレイアウト
と言ってもWebViewを追加するだけ

<?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>

プリントする画面

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

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.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

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;

  @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 &amp;&amp; resultCode == RESULT_OK) {
      dialogWebView.loadUrl(intent.getStringExtra("SCAN_RESULT"));
    }
  }

  final class PrintDialogJavaScriptInterface {
    @JavascriptInterface
    public String getType() {
      return cloudPrintIntent.getType();
    }

    @JavascriptInterface
    public String getTitle() {
      return cloudPrintIntent.getExtras().getString("title");
    }

    @JavascriptInterface
    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 &gt;= 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 "";
    }

    @JavascriptInterface
    public String getEncoding() {
      return CONTENT_TRANSFER_ENCODING;
    }

    @JavascriptInterface
    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)");
      }
    }
  }
}

公式と違うところはPrintDialogJavaScriptInterfaceクラスにある関数に『@JavascriptInterface』を付け加えています。
これはAndroid4.2からの仕様変更によるもので、JavaScriptからメソッドを呼び出すためには@JavascriptInterfaceアノテーションを付けたpublicメソッドではないといけないらしいです。

これで印刷も問題なく動作しましたー

This entry was posted in Android, プログラミング関連, 備忘録. Bookmark the permalink.

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です