Release apk Android Java 中 onMessageReceived 方法中信号器的 Gson 解析失败
我成功地在Android Java代码中实现了SignalR。
一切正常。我能够建立连接,发送和接收消息。
但是,当我在签名的版本APK中测试功能时,我会在onMessageCeepield中登录以下登录:
2022-03-27 11:52:42.725 8615-14192/? E/onMessageReceived: {"I":null}
通常 {“ i”:“ 0”}
我收到的所有其他JSON都会发生这种情况。
在我理解的程度上,这是因为GSON无法做到的在签名的版本APK中正确解析JSON。
我做了
minifyEnabled false
shrinkResources false
,事情开始在签名的释放APK中行动正常。
mHubConnection.received(new MessageReceivedHandler() {
@Override
public void onMessageReceived(final JsonElement json) {
Log.e("onMessageReceived ", json.toString());
mHandler.post(new Runnable() {
@Override
public void run() {
try {
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
我浏览了各种网页,并将以下行添加到proguard-rules.pro,但是在这方面没有任何变化:
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# Gson specific classes
#-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.** { *; }
-keep class com.google.code.** { *; }
-keep class com.google.gson.JsonParser.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.mychatapp.models.** { *; }
-keep class com.mychatapp.util.** { *; }
-keep class com.mychatapp.chat.** { *; }
-keep class com.microsoft.signalr.** { *; }
-keep interface com.microsoft.signalr.** { *; }
# Gson specific classes
-dontwarn sun.misc.**
-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
edit
/strong 这样的服务:
Intent intent = new Intent();
intent.putExtra(Constants.INTENT_USER_NAME, userName);
intent.putExtra(Constants.INTENT_GROUP_CODE, groupCode);
intent.putExtra(Constants.INTENT_GROUP_NAME, groupName);
intent.setClass(this, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
这是我的服务代码,我在其中创建连接并接收消息:
public class SignalRService extends Service {
private final static String TAG = "SignalRService";
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler;
private final IBinder mBinder = new LocalBinder();
private final String SERVER_URL = "";
private final String SERVER_HUB_CHAT_NAME = "MyHub";
private final String SET_USER_NAME = "SetUserName";
private final String JOIN_GROUP = "JoinGroup";
private String userName;
private String groupName;
private String groupCode;
private String accessToken;
private ArrayList<Message> messageList = new ArrayList<>();
public HubProxy getHubProxy() {
return mHubProxy;
}
public SignalRService() {
}
@Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
return result;
}
@Override
public void onDestroy() {
mHubConnection.stop();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
connect();
onMessageReceived();
return mBinder;
}
public class LocalBinder extends Binder {
public SignalRService getService() {
// Return this instance of SignalRService so clients can call public methods
return SignalRService.this;
}
}
public void connect() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mHubConnection = new HubConnection(SERVER_URL);
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT_NAME);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
mHandler.post(new Runnable() {
@Override
public void run() {
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
Log.i("CONNECTION", "before connection");
signalRFuture.get();
Log.i("CONNECTION", "after connection");
mHubProxy.invoke(SET_USER_NAME, new Object[]{userName});
Log.e("Connection", mHubConnection.getConnectionData());
JSONArray jsonArray = new JSONArray(mHubConnection.getConnectionData());
JSONObject jsonObject = jsonArray.getJSONObject(0);
String name = jsonObject.getString("name");
if(name.equalsIgnoreCase(SERVER_HUB_CHAT_NAME)) {
Log.i(TAG, "Connected!");
sendBroadcast(Constants.ACTION_CONNECTION, "Connected");
} else {
Log.i(TAG, "Connection Failed");
sendBroadcast(Constants.ACTION_CONNECTION, "Connection Failed");
}
} catch (InterruptedException | ExecutionException | JSONException e) {
Log.e(TAG, e.toString());
Toast.makeText(SignalRService.this, "Connection Failed!", Toast.LENGTH_LONG).show();
sendBroadcast(Constants.ACTION_CONNECTION, "Connection Failed");
}
}
});
}
public void onMessageReceived() {
mHubConnection.received(new MessageReceivedHandler() {
@Override
public void onMessageReceived(final JsonElement json) {
Log.e("onMessageReceived ", json.toString() + " " + groupName);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
JSONObject jsonObject = new JSONObject(json.toString());
if(jsonObject.has("A")) {
JSONArray jsonArray = jsonObject.getJSONArray("A");
final Message message = new Message();
final String user = jsonArray.get(0).toString();
final String receivedMsg = jsonArray.get(1).toString();
message.setMessage(receivedMsg);
// set message type (self or other)
message.setSelf(user.equalsIgnoreCase(userName));
message.setUserName(user);
Calendar cal = Calendar.getInstance();
String hour = String.format(Locale.US, "%02d", cal.get(Calendar.HOUR_OF_DAY));
String minute = String.format(Locale.US, "%02d", cal.get(Calendar.MINUTE));
final String time = hour + ":" + minute;
message.setDateAndTime(time);
messageList.add(message);
sendBroadcast(Constants.ACTION_MESSAGE, "");
} else if(jsonObject.has("I")) {
final String value = jsonObject.getString("I");
if(value.equals("0")) {
mHubProxy.invoke(JOIN_GROUP, groupName, accessToken, groupCode);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
private void sendBroadcast(final String action, final String connectionMsg) {
Intent local = new Intent();
local.setAction(action);
if(action.equals(Constants.ACTION_CONNECTION)) {
local.putExtra(Constants.INTENT_CONNECTION_STATUS, connectionMsg);
} else if(action.equals(Constants.ACTION_MESSAGE)) {
local.putExtra(Constants.INTENT_MESSAGE_LIST, messageList);
}
sendBroadcast(local);
}
}
当信号码库调用OnMessageCeived时,方法参数jsonelement将转换为字符串并显示在日志中。
直接在设备和模拟器上运行该应用程序时,日志显示为:
2022-03-27 11:52:42.725 8615-14192/? E/onMessageReceived: {"I":"0"}
,当使用签名的reneateAse APK在设备上完成此操作时,我得到:
2022-03-27 11:52:42.725 8615-14192/? E/onMessageReceived: {"I":null}
我需要指出,这是来自后端,而任何JSONELEMENT都提供了。信号在日志中显示。如果我设置
minifyEnabled false
shrinkResources false
此设置,也将返回版本APK中的正确JSON。
I was successful in implementing SignalR in Android Java code.
Everything is working fine. I was able to make connection, send and receive messages.
But, when I am testing the functionality in the signed release apk, I get the following log in onMessageReceived:
2022-03-27 11:52:42.725 8615-14192/? E/onMessageReceived: {"I":null}
which normally is like
{"I": "0"}
this happens with all the other jsons I recieve.
To the extent I understand, this is happening because of GSON which is not able to parse the json correctly in the signed release apk.
I made
minifyEnabled false
shrinkResources false
and things started to act normal in signed release apk.
mHubConnection.received(new MessageReceivedHandler() {
@Override
public void onMessageReceived(final JsonElement json) {
Log.e("onMessageReceived ", json.toString());
mHandler.post(new Runnable() {
@Override
public void run() {
try {
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
I went through various webpages and added the below lines to the proguard-rules.pro, but nothing changes in this regard:
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# Gson specific classes
#-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.** { *; }
-keep class com.google.code.** { *; }
-keep class com.google.gson.JsonParser.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.mychatapp.models.** { *; }
-keep class com.mychatapp.util.** { *; }
-keep class com.mychatapp.chat.** { *; }
-keep class com.microsoft.signalr.** { *; }
-keep interface com.microsoft.signalr.** { *; }
# Gson specific classes
-dontwarn sun.misc.**
-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
EDIT
I have kept the connection part and receiver part in a Service and I am calling the service like this:
Intent intent = new Intent();
intent.putExtra(Constants.INTENT_USER_NAME, userName);
intent.putExtra(Constants.INTENT_GROUP_CODE, groupCode);
intent.putExtra(Constants.INTENT_GROUP_NAME, groupName);
intent.setClass(this, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Here is my service code where I am creating the connection and receiving the message:
public class SignalRService extends Service {
private final static String TAG = "SignalRService";
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler;
private final IBinder mBinder = new LocalBinder();
private final String SERVER_URL = "";
private final String SERVER_HUB_CHAT_NAME = "MyHub";
private final String SET_USER_NAME = "SetUserName";
private final String JOIN_GROUP = "JoinGroup";
private String userName;
private String groupName;
private String groupCode;
private String accessToken;
private ArrayList<Message> messageList = new ArrayList<>();
public HubProxy getHubProxy() {
return mHubProxy;
}
public SignalRService() {
}
@Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
return result;
}
@Override
public void onDestroy() {
mHubConnection.stop();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
connect();
onMessageReceived();
return mBinder;
}
public class LocalBinder extends Binder {
public SignalRService getService() {
// Return this instance of SignalRService so clients can call public methods
return SignalRService.this;
}
}
public void connect() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mHubConnection = new HubConnection(SERVER_URL);
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT_NAME);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
mHandler.post(new Runnable() {
@Override
public void run() {
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
Log.i("CONNECTION", "before connection");
signalRFuture.get();
Log.i("CONNECTION", "after connection");
mHubProxy.invoke(SET_USER_NAME, new Object[]{userName});
Log.e("Connection", mHubConnection.getConnectionData());
JSONArray jsonArray = new JSONArray(mHubConnection.getConnectionData());
JSONObject jsonObject = jsonArray.getJSONObject(0);
String name = jsonObject.getString("name");
if(name.equalsIgnoreCase(SERVER_HUB_CHAT_NAME)) {
Log.i(TAG, "Connected!");
sendBroadcast(Constants.ACTION_CONNECTION, "Connected");
} else {
Log.i(TAG, "Connection Failed");
sendBroadcast(Constants.ACTION_CONNECTION, "Connection Failed");
}
} catch (InterruptedException | ExecutionException | JSONException e) {
Log.e(TAG, e.toString());
Toast.makeText(SignalRService.this, "Connection Failed!", Toast.LENGTH_LONG).show();
sendBroadcast(Constants.ACTION_CONNECTION, "Connection Failed");
}
}
});
}
public void onMessageReceived() {
mHubConnection.received(new MessageReceivedHandler() {
@Override
public void onMessageReceived(final JsonElement json) {
Log.e("onMessageReceived ", json.toString() + " " + groupName);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
JSONObject jsonObject = new JSONObject(json.toString());
if(jsonObject.has("A")) {
JSONArray jsonArray = jsonObject.getJSONArray("A");
final Message message = new Message();
final String user = jsonArray.get(0).toString();
final String receivedMsg = jsonArray.get(1).toString();
message.setMessage(receivedMsg);
// set message type (self or other)
message.setSelf(user.equalsIgnoreCase(userName));
message.setUserName(user);
Calendar cal = Calendar.getInstance();
String hour = String.format(Locale.US, "%02d", cal.get(Calendar.HOUR_OF_DAY));
String minute = String.format(Locale.US, "%02d", cal.get(Calendar.MINUTE));
final String time = hour + ":" + minute;
message.setDateAndTime(time);
messageList.add(message);
sendBroadcast(Constants.ACTION_MESSAGE, "");
} else if(jsonObject.has("I")) {
final String value = jsonObject.getString("I");
if(value.equals("0")) {
mHubProxy.invoke(JOIN_GROUP, groupName, accessToken, groupCode);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
private void sendBroadcast(final String action, final String connectionMsg) {
Intent local = new Intent();
local.setAction(action);
if(action.equals(Constants.ACTION_CONNECTION)) {
local.putExtra(Constants.INTENT_CONNECTION_STATUS, connectionMsg);
} else if(action.equals(Constants.ACTION_MESSAGE)) {
local.putExtra(Constants.INTENT_MESSAGE_LIST, messageList);
}
sendBroadcast(local);
}
}
When onMessageReceived is called by the SignalR code libraries, the method argument JsonElement is converted to string and displayed in the log.
When running the app directly on device and emulator the log is displayed as:
2022-03-27 11:52:42.725 8615-14192/? E/onMessageReceived: {"I":"0"}
And, when this is done on a device using a signed releaase apk, I get:
2022-03-27 11:52:42.725 8615-14192/? E/onMessageReceived: {"I":null}
I need to point out that this is coming from backend and whatever JsonElement is provided by SignalR is displayed in the log. If I set
minifyEnabled false
shrinkResources false
This returns the correct json in the release apk as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论