我目前正在开发用于连接到 Google Cloud IoT Core 的 Android Things 程序。我曾经对 Google 提供的 maven 代码进行采样,并针对 Gradle 进行了修改(包含所有导入和内容)。在进行各种检查后,每当我尝试在运行 Android Things 的 Raspberry Pi3 上运行程序时,它都会一直出现此错误
W/System.err: java.io.FileNotFoundException: com/example/adityaprakash/test/rsa_private.pem (No such file or directory)
告诉我我应该用于 JWT 的私钥文件不存在,尽管它确实存在,并且我已经给出了 pem 文件的路径。这是我的 java 代码
package com.example.adityaprakash.test;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
Log.i("#########","######");
MqttExample mqtt = new MqttExample();
try {
mqtt.Start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
MqttExample.java
package com.example.adityaprakash.test;
// [END cloudiotcore_mqtt_imports]
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.joda.time.DateTime;
import java.io.BufferedReader;
import java.io.FileReader;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import android.util.Base64;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class MqttExample {
// [START cloudiotcore_mqtt_createjwt]
/** Create a Cloud IoT Core JWT for the given project id, signed with the given RSA key. */
public static String createJwtRsa(String projectId, String privateKeyFile) throws Exception {
DateTime now = new DateTime();
String strKeyPEM = "";
BufferedReader br = new BufferedReader(new FileReader(privateKeyFile));
String line;
while ((line = br.readLine()) != null) {
strKeyPEM += line + "\n";
}
br.close();
// Create a JWT to authenticate this device. The device will be disconnected after the token
// expires, and will have to reconnect with a new token. The audience field should always be set
// to the GCP project id.
JwtBuilder jwtBuilder =
Jwts.builder()
.setIssuedAt(now.toDate())
.setExpiration(now.plusMinutes(20).toDate())
.setAudience(projectId);
String privateKeyPEM = strKeyPEM;
privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decode(privateKeyPEM,Base64.DEFAULT);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return jwtBuilder.signWith(SignatureAlgorithm.RS256, kf.generatePrivate(spec)).compact();
}
/** Parse arguments, configure MQTT, and publish messages. */
public void Start() throws Exception {
// [START cloudiotcore_mqtt_configuremqtt]
MqttExampleOptions options = MqttExampleOptions.values();
if (options == null) {
// Could not parse.
System.exit(1);
}
// Build the connection string for Google's Cloud IoT Core MQTT server. Only SSL
// connections are accepted. For server authentication, the JVM's root certificates
// are used.
final String mqttServerAddress =
String.format("ssl://%s:%s", options.mqttBridgeHostname, options.mqttBridgePort);
// Create our MQTT client. The mqttClientId is a unique string that identifies this device. For
// Google Cloud IoT Core, it must be in the format below.
final String mqttClientId =
String.format(
"projects/%s/locations/%s/registries/%s/devices/%s",
options.projectId, options.cloudRegion, options.registryId, options.deviceId);
MqttConnectOptions connectOptions = new MqttConnectOptions();
// Note that the the Google Cloud IoT Core only supports MQTT 3.1.1, and Paho requires that we
// explictly set this. If you don't set MQTT version, the server will immediately close its
// connection to your device.
connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
// With Google Cloud IoT Core, the username field is ignored, however it must be set for the
// Paho client library to send the password field. The password field is used to transmit a JWT
// to authorize the device.
connectOptions.setUserName("unused");
System.out.println(options.algorithm);
if (options.algorithm.equals("RS256")) {
connectOptions.setPassword(
createJwtRsa(options.projectId, options.privateKeyFile).toCharArray());
}else {
throw new IllegalArgumentException(
"Invalid algorithm " + options.algorithm + ". Should be one of 'RS256' or 'ES256'.");
}
// [END cloudiotcore_mqtt_configuremqtt]
// [START cloudiotcore_mqtt_publish]
// Create a client, and connect to the Google MQTT bridge.
MqttClient client = new MqttClient(mqttServerAddress, mqttClientId, new MemoryPersistence());
try {
client.connect(connectOptions);
// Publish to the events or state topic based on the flag.
String subTopic = options.messageType.equals("event") ? "events" : options.messageType;
// The MQTT topic that this device will publish telemetry data to. The MQTT topic name is
// required to be in the format below. Note that this is not the same as the device registry's
// Cloud Pub/Sub topic.
String mqttTopic = String.format("/devices/%s/%s", options.deviceId, subTopic);
// Publish numMessages messages to the MQTT bridge, at a rate of 1 per second.
for (int i = 1; i <= options.numMessages; ++i) {
String payload = String.format("%s/%s-payload number-%d", options.registryId, options.deviceId, i);
System.out.format(
"Publishing %s message %d/%d: '%s'\n",
options.messageType, i, options.numMessages, payload);
// Publish "payload" to the MQTT topic. qos=1 means at least once delivery. Cloud IoT Core
// also supports qos=0 for at most once delivery.
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(1);
client.publish(mqttTopic, message);
if (options.messageType.equals("event")) {
// Send telemetry events every second
Thread.sleep(1000);
}
else {
// Note: Update Device state less frequently than with telemetry events
Thread.sleep(5000);
}
}
} finally {
// Disconnect the client and finish the run.
client.disconnect();
}
System.out.println("Finished loop successfully. Goodbye!");
// [END cloudiotcore_mqtt_publish]
}
}
和 MqttExampleOptions.java 代码:
package com.example.adityaprakash.test;
public class MqttExampleOptions {
String projectId;
String registryId;
String deviceId;
String privateKeyFile;
String algorithm;
String cloudRegion;
int numMessages;
String mqttBridgeHostname;
short mqttBridgePort;
String messageType;
/** Construct an MqttExampleOptions class. */
public static MqttExampleOptions values() {
try {
MqttExampleOptions res = new MqttExampleOptions();
res.projectId = "_";
res.registryId = "_";
res.deviceId = "_";
res.privateKeyFile = "com/example/adityaprakash/test/rsa_private.pem";
res.algorithm = "RS256";
res.cloudRegion = "asia-east1";
res.numMessages = 100;
res.mqttBridgeHostname = "mqtt.googleapis.com";
res.mqttBridgePort = 8883;
res.messageType = "event";
return res;
} catch (Exception e) {
System.err.println(e.getMessage());
return null;
}
}
}
请任何人都可以解决这个问题。
PS我知道代码看起来很糟糕。我没有Android编程经验,所以请放手。