我将我的JavaFX应用程序移植到我的Android设备上。我希望我的应用程序读取传入的SMS消息并将其存储在数据库中。我在StackOverflow中找到了几个问题,但我不知道如何在JavaFX方法中实现。请帮忙!
答案 0 :(得分:6)
这些是创建JavaFX应用程序并将其移植到Android设备所需的步骤,因此您可以跟踪SMS消息,从而允许:
第1步
对NetBeans使用Gluon plugin创建一个新的JavaFX项目。让我们称之为SMSTracker,主类为org.jpereda.sms.SMSTrackerFX
。在build.gradle
上,将jfxmobile插件版本更新为b9:
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.0-b9'
}
首先让我们用我们的模型创建一个JavaFX pojo SMSMessage
:
public class SMSMessage {
private final StringProperty id;
private final StringProperty address;
private final StringProperty msg;
private final StringProperty readState; //"0" not read, "1" read sms
private final StringProperty time;
private final StringProperty folderName;
public SMSMessage(String id, String address, String msg, String readState, String time, String folderName){
this.id = new SimpleStringProperty(id);
this.address = new SimpleStringProperty(address);
this.msg = new SimpleStringProperty(msg);
this.readState = new SimpleStringProperty(readState);
this.time = new SimpleStringProperty(time);
this.folderName = new SimpleStringProperty(folderName);
}
public String getId() {
return id.get();
}
public StringProperty idProperty() {
return id;
}
public String getAddress() {
return address.get();
}
public StringProperty addressProperty() {
return address;
}
public String getMsg() {
return msg.get();
}
public StringProperty msgProperty() {
return msg;
}
public String getReadState() {
return readState.get();
}
public StringProperty readStateProperty() {
return readState;
}
public String getTime() {
return time.get();
}
public StringProperty timeProperty() {
return time;
}
public String getFolderName() {
return folderName.get();
}
public StringProperty folderNameProperty() {
return folderName;
}
@Override
public String toString(){
return id.get()+ ": " + address.get() + ": " + msg.get();
}
}
使用ScenicBuilder和FXML或代码,创建您的UI。对于此示例,它将是一个简单的UI,包含三个主要区域,用于上述三个选项。
public class SMSTrackerFX extends Application {
@Override
public void start(Stage stage) {
BorderPane root = new BorderPane();
/*
TOP :: Sending SMS
Warning: This may by subjected to costs to your mobile account
*/
Button buttonSend = new Button("Send SMS");
TextField number = new TextField();
number.setPromptText("Insert number");
HBox.setHgrow(number, Priority.ALWAYS);
HBox hbox = new HBox(10,buttonSend, number);
TextField message = new TextField();
message.setPromptText("Insert text");
HBox.setHgrow(message, Priority.ALWAYS);
VBox vboxTop = new VBox(10,hbox,message);
buttonSend.disableProperty().bind(Bindings.createBooleanBinding(()->{
return number.textProperty().isEmpty()
.or(message.textProperty().isEmpty()).get();
}, number.textProperty(),message.textProperty()));
vboxTop.setPadding(new Insets(10));
root.setTop(vboxTop);
/*
CENTER :: Reading SMS Inbox
*/
Button button = new Button("Read SMS Inbox");
ListView<SMSMessage> view = new ListView<>();
view.setCellFactory(data -> new SMSListCell());
VBox.setVgrow(view, Priority.ALWAYS);
VBox vboxCenter = new VBox(10,button,view);
vboxCenter.setPadding(new Insets(10));
root.setCenter(vboxCenter);
/*
BOTTOM :: Listening to incoming SMS
*/
Label incoming = new Label("No messages");
VBox vboxBottom = new VBox(10,new Label("Incoming SMS"),incoming);
vboxBottom.setPadding(new Insets(10));
root.setBottom(vboxBottom);
Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
Scene scene = new Scene(root, visualBounds.getWidth(), visualBounds.getHeight());
stage.setScene(scene);
stage.show();
}
private static class SMSListCell extends ListCell<SMSMessage> {
@Override
protected void updateItem(SMSMessage item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setGraphic(new Label(item.getId()+ ": " + item.getMsg()));
} else {
setGraphic(null);
}
}
}
}
这就是我们现在所拥有的:
第2步
关注HelloPlatform sample,我们将添加PlatformService
类和PlatformProvider
接口以及所需的服务:
public interface PlatformProvider {
void sendSMS(String number, String message);
List<SMSMessage> readSMSs();
void listenToIncomingSMS();
ObjectProperty<SMSMessage> messageProperty();
}
此界面将在三个平台(桌面,iOS和Android)中的每一个上实现。显然,我们只关注Android实现。
这是NetBeans上包含所有包和文件的项目视图:
第3步
让我们现在实现Android上的服务。为此,我在SO上听了几个很棒的答案:发送SMS,阅读inbox并听取传入的SMS。
从最后一个开始,我们可以创建一个类,每次收到一个ObjectProperty
时都会设置一个SMSMessage
对象:
public class SmsListener extends BroadcastReceiver {
private final ObjectProperty<SMSMessage> messages = new SimpleObjectProperty<>();
@Override
public void onReceive(Context cntxt, Intent intent) {
if(intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)){
for (SmsMessage smsMessage : Intents.getMessagesFromIntent(intent)) {
SMSMessage sms = new SMSMessage("0", smsMessage.getOriginatingAddress(),
smsMessage.getMessageBody(), smsMessage.getStatus()==1?"read":"not read",
Long.toString(smsMessage.getTimestampMillis()), "inbox");
messages.set(sms);
}
}
}
public ObjectProperty<SMSMessage> messagesProperty() {
return messages;
}
}
为了启动这个监听器,我们使用FXActivity
扩展Android Context类并提供对Android服务的访问的类来注册SmsListener
的实例:
public class AndroidPlatformProvider implements PlatformProvider {
private final SmsListener receiver = new SmsListener();
@Override
public void listenToIncomingSMS() {
FXActivity.getInstance().registerReceiver(receiver, new IntentFilter(Intents.SMS_RECEIVED_ACTION));
}
@Override
public ObjectProperty<SMSMessage> messagesProperty() {
return receiver.messagesProperty();
}
}
第4步
最后,我们需要做的就是将属性与UI上的标签绑定并启动广播:
@Override
public void start(Stage stage) {
...
PlatformService.getInstance().messageProperty().addListener(
(obs,s,s1)->{
Platform.runLater(()->incoming.setText(s1.toString()));
});
// start broadcast
PlatformService.getInstance().listenToIncomingSMS();
}
请注意使用Platform.runLater()
更新标签:广播线程与JavaFX线程不同。
第5步
构建apk之前的最后一步是修改AndroidManifest.xml
文件以询问所需的权限。
由于jfxmobile-plugin默认创建一个,因此在此阶段运行gradlew android
将生成它。它位于SMSTracker\build\javafxports\tmp\android
文件夹下。
将其复制到其他位置(SMSTracker\lib
)并在build.gradle
文件中包含其引用:
jfxmobile {
android {
manifest = 'lib/AndroidManifest.xml'
}
}
现在编辑文件并添加所需的权限和接收者:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jpereda.sms" android:versionCode="1" android:versionName="1.0">
<supports-screens android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="21"/>
<application android:label="SMSTracker" android:name="android.support.multidex.MultiDexApplication">
<activity android:name="javafxports.android.FXActivity" android:label="SMSTracker" android:configChanges="orientation|screenSize">
<meta-data android:name="main.class" android:value="org.jpereda.sms.SMSTrackerFX"/>
<meta-data android:name="debug.port" android:value="0"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name=".SmsListener">
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
保存,构建并运行gradlew androidInstall
以将apk上传到您的设备。
完整项目