有人可以告诉我是否可以使用 google cloud print 从 android 设备进行静默打印?目标是我的应用程序从 URL 或 SD 卡中获取文件,然后将其发送到特定的打印机 - 所有这些都无需任何人查看屏幕或触摸任何东西进行交互。它实际上是由蓝牙连接设备上的条形码扫描触发的。
谢谢
有人可以告诉我是否可以使用 google cloud print 从 android 设备进行静默打印?目标是我的应用程序从 URL 或 SD 卡中获取文件,然后将其发送到特定的打印机 - 所有这些都无需任何人查看屏幕或触摸任何东西进行交互。它实际上是由蓝牙连接设备上的条形码扫描触发的。
谢谢
嗯,这是可能的,但我不知道为什么文档中没有太多关于它的信息......
棘手的部分是仅使用 android 设备连接到谷歌云打印 API(没有第三方服务器,如文档在此处解释:https ://developers.google.com/cloud-print/docs/appDevGuide ),这就是我来解释一下。
首先,您必须在您的应用中包含 Google 登录 API,我推荐使用 firebase API https://firebase.google.com/docs/auth/android/google-signin
然后你必须去你的谷歌 API 控制台:https://console.developers.google.com在菜单中,去凭证滚动到OAuth 2.0 客户端 ID选择Web 客户端(由谷歌服务自动创建)并保存到你的项目中客户端ID和客户端密钥...在我的项目中,我将它们保存为“ gg_client_web_id ”和“ gg_client_web_secret ”,您将在下面的代码中看到。
接下来,我将粘贴所有代码,然后我将对其进行解释:
public class MainActivity extends AppCompatActivity
implements GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private static final int REQUEST_SINGIN = 1;
private TextView txt;
public static final String TAG = "mysupertag";
public static final String URLBASE = "https://www.google.com/cloudprint/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = (TextView) findViewById(R.id.txt);
mAuth = FirebaseAuth.getInstance();
// Configure Google Sign In
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.gg_client_web_id))
.requestEmail()
.requestServerAuthCode(getString(R.string.gg_client_web_id))
.requestScopes(new Scope("https://www.googleapis.com/auth/cloudprint"))
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
signIn();
}
});
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// ...
}
};
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.d(TAG, "error connecting: " + connectionResult.getErrorMessage());
Toast.makeText(this, "error CONN", Toast.LENGTH_LONG).show();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == REQUEST_SINGIN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = result.getSignInAccount();
firebaseAuthWithGoogle(account);
} else {
// Google Sign In failed, update UI appropriately
// ...
Toast.makeText(this, "error ", Toast.LENGTH_LONG).show();
}
}
}
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, REQUEST_SINGIN);
}
@Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
private void firebaseAuthWithGoogle(final GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
FirebaseUser user = task.getResult().getUser();
txt.setText(user.getDisplayName() + "\n" + user.getEmail());//todo
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithCredential", task.getException());
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
getAccess(acct.getServerAuthCode());
}
});
}
private void getPrinters(String token) {
Log.d(TAG, "TOKEN: " + token);
String url = URLBASE + "search";
Ion.with(this)
.load("GET", url)
.addHeader("Authorization", "Bearer " + token)
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
@Override
public void onCompleted(Exception e, Response<String> result) {
Log.d(TAG, "finished " + result.getHeaders().code() + ": " +
result.getResult());
if (e == null) {
Log.d(TAG, "nice");
} else {
Log.d(TAG, "error");
}
}
});
}
private void getAccess(String code) {
String url = "https://www.googleapis.com/oauth2/v4/token";
Ion.with(this)
.load("POST", url)
.setBodyParameter("client_id", getString(R.string.gg_client_web_id))
.setBodyParameter("client_secret", getString(R.string.gg_client_web_secret))
.setBodyParameter("code", code)
.setBodyParameter("grant_type", "authorization_code")
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
@Override
public void onCompleted(Exception e, Response<String> result) {
Log.d(TAG, "result: " + result.getResult());
if (e == null) {
try {
JSONObject json = new JSONObject(result.getResult());
getPrinters(json.getString("access_token"));
} catch (JSONException e1) {
e1.printStackTrace();
}
} else {
Log.d(TAG, "error");
}
}
});
}}
如您所见,在 onCreate 中,重要的部分是使用谷歌云打印范围创建GoogleSignInOptions并调用 requestIdToken/requestServerAuthCode 方法。
然后在firebaseAuthWithGoogle方法中调用getAccess方法以获取 OAuth 访问令牌,以发出我使用 Ion 库的所有请求:https ://github.com/koush/ion
接下来使用 access_token,您现在可以向谷歌云打印 API 发出请求,在这种情况下,我调用getPrinters方法,在此方法中,我调用“搜索”方法(来自谷歌云打印 API)来获取与已登录的 google 帐户..(要将打印机关联到 google 帐户,请访问:https ://support.google.com/cloudprint/answer/1686197?hl=en&p=mgmt_classic )注意.addHeader("Authorization" , "Bearer" + token),这是请求的重要部分,"token" var 是 access_token,您需要添加此 Authorization 标头才能使用 API,并且不要忘记在到期时刷新,如在这里解释:https://developers.google.com/identity/protocols/OAuth2ForDevices在“使用刷新令牌”部分。
就是这样,你现在可以打印一些发送 POST 请求到谷歌云打印 API 的“提交”方法的东西,我建议去这里:https ://developers.google.com/cloud-print/docs/appInterfaces和查看所有可用的方法以及如何使用它们(发送给它们的参数等)。当然,在那个链接中也解释了“提交”方法。
编辑:
如何向“/submit”发送请求以使用 ION 库和 MJSON 库 ( https://bolerio.github.io/mjson/ ) 进行打印的示例 MJSON 用于创建 JSON 对象,您可以按照自己的方式创建它更喜欢
private void printPdf(String pdfPath, String printerId) {
String url = URLBASE + "submit";
Ion.with(this)
.load("POST", url)
.addHeader("Authorization", "Bearer " + YOUR_ACCESS_TOKEN)
.setMultipartParameter("printerid", printerId)
.setMultipartParameter("title", "print test")
.setMultipartParameter("ticket", getTicket())
.setMultipartFile("content", "application/pdf", new File(pdfPath))
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
@Override
public void onCompleted(Exception e, Response<String> result) {
if (e == null) {
Log.d(TAG, "PRINTTT CODE: " + result.getHeaders().code() +
", RESPONSE: " + result.getResult());
Json j = Json.read(result.getResult());
if (j.at("success").asBoolean()) {
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "ERROR", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(MainActivity.this, "ERROR", Toast.LENGTH_LONG).show();
Log.d(TAG, e.toString());
}
}
});
}
private String getTicket() {
Json ticket = Json.object();
Json print = Json.object();
ticket.set("version", "1.0");
print.set("vendor_ticket_item", Json.array());
print.set("color", Json.object("type", "STANDARD_MONOCHROME"));
print.set("copies", Json.object("copies", 1));
ticket.set("print", print);
return ticket.toString();
}
是的,您可以使用此 REST API ( https://www.google.com/cloudprint/submit ) 实现静默打印,我使用 WCF 服务完成了它。您需要从 url 下载内容作为 base64 内容,然后添加
contentType=dataUrl
在请求中。这是代码..
postData = "printerid=" + PrinterId;
postData += "&title=" + JobTitle;
postData += "&ticket=" + ticket;
postData += "&content=data:" + documentContent.ContentType + ";base64," + documentContent.Base64Content;
postData += "&contentType=dataUrl";
postData += "&tag=test";
然后,请以这种方式提出提交 REST API 的请求。
var request = (HttpWebRequest)WebRequest.Create("https://www.google.com/cloudprint/submit");
var data = Encoding.ASCII.GetBytes(postData);
request.Headers.Add("Authorization: Bearer " + Token);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
request.UseDefaultCredentials = true;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
PrintJobResponse printInfo = json_serializer.Deserialize<PrintJobResponse>(responseString);
return printInfo;
谢谢。
对于现在阅读本文的任何人,经过大量搜索后,我发现设置为仅使用 Zapier 捕捉钩子并打印到谷歌云打印(至少来自科尔多瓦,我不会说话对于本机应用程序)