How to get versionCode of app outside my own? - java

I am attempting to add a function to that will check a json file on my server for the versionCode of an app outside of my own and if the versionCode in json on the server is greater than the one of the app outside of my own, then do an update action.
The update action works fine, however, I am experiencing issues getting the versionCode of the outside app. The versionCode always returns as 0 instead of the actual version of the outside app.
Why doesn't it return the proper version?
Here is my code for fetching the versionCode of the other app:
public static int getinstVersionCode(Context mContext) {
if (mContext != null) {
try {
return mContext.getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0).versionCode;
} catch (PackageManager.NameNotFoundException ignored) {
}
}
return 0;
}
The PACKAGE_NAME equals the com.example.app app package name that is held in the json file on my server:
static final String APK_VERSION_CODE = "versionCode";
static final String PACKAGE_NAME = "package";
And finally, the json file itself:
"versionCode":0,
"package":"com.example.app",

Check the exception, the application which version you are trying to get must be present on the device and exactly match the package name.

Related

Android studio updated and code too large now

I have a system that has been produced for 2 years now. It is an EMM system for controlling corporate devices.
It uses FireBase to send the functionality executed on the device from the server app to the device.
There are around 400 possible commands you can send to a device and all these commands are handled in one class initially, which overrides the onMessageReceived() from the FireBaseMessagingService class.
The older version of Android studio built the apk which is now in production. I have started to work on version 2 of my system after about a year off. so I updated my Android studio to the latest (4).
The Problem:
when I try to build the project and push onto a device, I get
error: code too large public void onMessageReceived(RemoteMessage remoteMessage) {
As stated before this onMessageReceived method can handle 400 different types of push notifications from the server app, so there are a lot of if/else statements in the method body.
Is there any reason why since the AS upgrade this will not work?
is there any setting I can change in AS to get past this?
What I have tried:
I thought about putting half of the if/else in another service class, to cut down on the method code. This would involve passing the remoteMessageMap to another class to carry on with the if/else processing.
remoteMessageMap from FireBase is a Map and Maps are not serializable as they extend the interface, so can't pass it.
public class MyAndroidFirebaseMsgService extends FirebaseMessagingService {
private static final String TAG = "MyAndroidFCMService";
AppObj appObj;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.e(TAG, "remoteMessage.getData() = " + remoteMessage.getData());
Map remoteMessageMap = remoteMessage.getData();
String message = (String)remoteMessageMap.get("message");
thanks
[edit1]
else if(message.trim().equalsIgnoreCase("CLEARCACHE_REMOVE_APP_WL")){
Log.e(TAG, "received CLEARCACHE_REMOVE_APP_WL");
String pushGuid = (String)remoteMessageMap.get("pushguid");
Log.e(TAG, "pushGuid = " + pushGuid);
String clearCacheRemoveWhitelist = (String)remoteMessageMap.get("clear_cache_app_names");
Intent intentExecutePushCommand = new Intent( getApplicationContext(), ExecutePushCommandIntentService.class);
intentExecutePushCommand.putExtra("compID", MenuActivity.companyID);
intentExecutePushCommand.putExtra("command", message);
intentExecutePushCommand.putExtra("pushguid", pushGuid);
intentExecutePushCommand.putExtra("clear_cache_app_names", clearCacheRemoveWhitelist);
startService(intentExecutePushCommand);
}else if(message.trim().equalsIgnoreCase("CLEARCACHE_GET_PACKAGENAMES_WL")){
Log.e(TAG, "received CLEARCACHE_GET_PACKAGENAMES_WL");
String pushGuid = (String)remoteMessageMap.get("pushguid");
Log.e(TAG, "pushGuid = " + pushGuid);
Intent intentExecutePushCommand = new Intent( getApplicationContext(), ExecutePushCommandIntentService.class);
intentExecutePushCommand.putExtra("compID", MenuActivity.companyID);
intentExecutePushCommand.putExtra("command", message);
intentExecutePushCommand.putExtra("pushguid", pushGuid);
startService(intentExecutePushCommand);
}else if(message.trim().equalsIgnoreCase("CLEARCACHE_ADD_PACKAGENAME_WL")){
Log.e(TAG, "received CLEARCACHE_ADD_PACKAGENAME_WL");
String pushGuid = (String)remoteMessageMap.get("pushguid");
Log.e(TAG, "pushGuid = " + pushGuid);
String packageName = (String)remoteMessageMap.get("package_name");
Intent intentExecutePushCommand = new Intent( getApplicationContext(), ExecutePushCommandIntentService.class);
intentExecutePushCommand.putExtra("compID", MenuActivity.companyID);
intentExecutePushCommand.putExtra("command", message);
intentExecutePushCommand.putExtra("pushguid", pushGuid);
intentExecutePushCommand.putExtra("package_name", packageName);
startService(intentExecutePushCommand);
}
There is no need to pass the remoteMessageMap to another class. The source of the problem is the limitation in the java method size. Here is a piece of the official documentation of oracle which is related to this problem:
code_length
The value of the code_length item gives the number of bytes in the code array for this method.
The value of code_length must be greater than zero (as the code array must not be empty) and less than 65536.
The point is that your onMessageReceived method is too long, which is bigger than 64KB of compiled code. It is weird why it was compiled fine in previous versions of Android Studio :)
Anyway, the solution is to break the method into smaller fragments. My suggestion is fragmentation by some message types. For example:
private static final String COMMAND_1 = "COMMAND_1";
private static final String COMMAND_2 = "COMMAND_2";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.e(TAG, "remoteMessage.getData() = " + remoteMessage.getData());
Map remoteMessageMap = remoteMessage.getData();
String message = (String) remoteMessageMap.get("message");
String type = extrated_from_received_message;
switch (type) {
case COMMAND_1:
handleCommand1(remoteMessageMap);
break;
case COMMAND_2:
handleCommand2(remoteMessageMap);
break;
// more commands ...
default:
// ...
}
}
private void handleCommand1(Map remoteMessageMap){
// do whatever related to command 1
}
private void handleCommand2(Map remoteMessageMap){
// do whatever related to command 2
}
In this way, the method size would be optimized and the performance of calling it will be far improved.
It seems that you are repeating the same lines of code a lot of times, just put these lines of code and maybe a few more in a separate method that is called on each else if and this will reduce the size of onMessageReceived()
Intent intentExecutePushCommand = new Intent( getApplicationContext(), ExecutePushCommandIntentService.class);
intentExecutePushCommand.putExtra("compID", MenuActivity.companyID);
intentExecutePushCommand.putExtra("command", message);
intentExecutePushCommand.putExtra("pushguid", pushGuid);

onDataChanged acting weird

I'm trying to use my wearOS app to extend my Paint app. I tried sending a Bitmap to the wear app everytime a new point was added, but that caused horrible lag.
I tried serializing a Path array, but then quickly noticed I could just pass the three different paint features, (start, move, end) via points and functions.
This is my onMove attempt:
public void sendPoint(Point p)
{
long[] newPoint = new long[2];
newPoint[0] = p.x;
newPoint[1] = p.y;
PutDataMapRequest dataMap = PutDataMapRequest.create("/count");
dataMap.getDataMap().putLongArray("count", newPoint);
PutDataRequest request = dataMap.asPutDataRequest();
Task<DataItem> putTask = Wearable.getDataClient(this).putDataItem(request);
}
Before I get into onStart and onEnd - I'd like to point out with this exact code:
public void sendPaint(Bitmap b)
{
Bitmap bitmap = b;
Asset asset = createAssetFromBitmap(bitmap);
PutDataMapRequest dataMap = PutDataMapRequest.create("/image");
dataMap.getDataMap().putAsset("profileImageX", asset);
PutDataRequest request = dataMap.asPutDataRequest();
Task<DataItem> putTask = Wearable.getDataClient(this).putDataItem(request);
}
I was able to send my bitmap.
The reason I say this is weird is becasue all I did was change .putAsset
dataMap.getDataMap().putAsset("profileImageX", asset);
to .putLongArray
dataMap.getDataMap().putLongArray("count", newPoint);
Any ideas as to why this isn't working? I noticed sendData only works if the data is new, perhaps this is the issue. In that case, I'd like to know how to erase the "data" send after it is received and used in the WearOS app.
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
is needed in order to work also within your gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "your.applicationid" // needs to be the same in both modules
minSdkVersion 20
targetSdkVersion 23
versionCode 1
versionName "1.0"
targetCompatibility = '1.7'
}
...
Also as you say I think you need to put something that's really new all the time like System MillTimes
dataMap.getDataMap().putLong("Time",System.currentTimeMillis())

Check if package name changed

I want to protect my APK from reverse engineering, by showing Toast, or do something if package name changed, now if package changed the app will stop working.
if (getPackageName().compareTo("com.apk.example") != 0) {
String error = null;
error.getBytes();
}
You need to check both your package name and application id to make sure your app haven't been tampered with:
String yourPackageName = "com.apk.example"; // android package name
String packageName = getApplicationContext().getPackageName();
// can be different from your package name if you're using flavor
// in app.build.gradle,
String yourApplicationId = "com.apk.example";
if(packageName.equals(yourPackageName) && BuildConfig.APPLICATION_ID.equals(yourApplicationId)) {
// no problem here
} else {
// app is tampered, do something
}

Android configuration value in CI

I am new to android but already thinking if there is a way to include some important configurations for the app in continuous integration . We use visual studio online for build and release .
Example .
Currently we have Constants.java file which stores some imp configuration values like server URL which wil be different for each environment app is deployed on for example dev,test uat production , so currently that code needs to be manually checked before it goes in to vso for build and release . . Is it possible to somehow configure it in continuous integration of environment and pick from there so that manual check is not required ..
See this:
Look this function readApiKey() it reads the keys in from Environment or from a .properties file. Then look at this line:
buildConfigField("String", "API_PUBLIC_KEY", readApiKey(KeyType.PUBLIC_KEY)) it loads the string resource with the value.
If you have different builds with different values, that's where flavours comes in. You can read it up here.
apply plugin: 'com.android.application'
apply from: '../codequality/quality.gradle'
/*
* Read API key from CI server or from keys.properties file
*/
enum KeyType {
PUBLIC_KEY,
PRIVATE_KEY
}
def readApiKey(KeyType type) {
String apiKey = ""
if (System.getenv("CIENV")) {
if (type == KeyType.PUBLIC_KEY) {
apiKey = System.getenv("PB_KEY")
} else apiKey = System.getenv("PR_KEY")
} else {
Properties props = new Properties()
try {
props.load(new FileInputStream(new File(getRootDir().getAbsolutePath() + "/keys.properties")))
if (type == KeyType.PUBLIC_KEY) {
apiKey = props.getProperty("api_pb_key")
} else apiKey = props.getProperty("api_pr_key")
} catch (FileNotFoundException fnfe) {
println("Please create a keys.properties file in the root directory of the project")
}
}
return "\"$apiKey\"";
}
println 'PUBLIC KEY Log' + readApiKey(KeyType.PUBLIC_KEY)
println 'Private Key Log' + readApiKey(KeyType.PRIVATE_KEY)
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
dataBinding {
enabled true
}
testOptions {
unitTests.returnDefaultValues = true
}
defaultConfig {
applicationId "co.tonespy.dummarvel"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// Setting up picked up data to String resource
buildConfigField("String", "API_PUBLIC_KEY", readApiKey(KeyType.PUBLIC_KEY))
buildConfigField("String", "API_PRIVATE_KEY", readApiKey(KeyType.PRIVATE_KEY))
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
// support dependencies
....
// test dependencies
testCompile "junit:junit:$jUnitVersion"
androidTestCompile("com.android.support.test.espresso:espresso-core:$espressoCoreVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile "org.mockito:mockito-core:$mockitoVersion"
compile "com.android.support:support-v4:$supportLibraryVersion"
}
You can just use Replace Tokens step/task to replace the value per to each environment.
Install Replace Tokens extension
Add Replace Tokens task to each environment of your release definition (Target files **\ Constants.java)
Add environment variable (e.g server, same variable name for each environment) for each environment of you release definition
Modify Constants.java file, replace necessary value to #{server}# and check in changes (The developers can modify this file with specific value and do not check in changes if they need to debug/run app in local machine)
After that the #{server}# will be replaced with the value of server environment

how to identify whether the OS is Linux desktop or Android? [duplicate]

This question already has answers here:
How do I programmatically determine operating system in Java?
(22 answers)
Closed 3 years ago.
I have an app that runs on several mobile devices running either Fedora or Android. To consolidate my codebase and distribution I would like to determine which OS I am on. I tried System.getProperty("os.name"), but that just returns "Linux". Is there something unique to Android in the System properties?
Thanks
There are several properties you could check. Candidates are:
java.vendor.url --> http://www.android.com
java.vm.name --> Dalvik (I don't know, which one Fedora is using...)
java.vm.vendor --> The Android Project
java.vendor --> The Android Project
Maybe you want to check by yourself?
Properties p = System.getProperties();
Enumeration keys = p.keys();
while(keys.hasMoreElements()) {
String key = (String) keys.nextElement();
String value = (String) p.get(key);
System.out.println(key + " >>>> " + value);
}
I do not know Android but if you do not find some unique system property you can sometimes identify the system if some specific class exists there. So you can do the following:
boolean isAndroid() {
try {
Class.forName("the class name");
return true;
} catch(ClassNotFoundException e) {
return false;
}
}
Here is some code that I wrote using the information from this page, in case you want to copy-paste:
private static YLogger ylogger;
public static YLogger getLogger() {
if (ylogger == null){
// need to find a new logger. Let's check if we have Android running
if (System.getProperty("java.vm.name").equalsIgnoreCase("Dalvik")){
ylogger = new AndroidLogger();
ylogger.d("YLoggerFactory", "Instantiating Android-based logger");
} else {
// fallback option, system logger.
ylogger = new SystemLogger();
ylogger.d("YLoggerFactory", "Instantiating System-based logger");
}
}
return ylogger;
}
The list of defined system properties is here: https://developer.android.com/reference/java/lang/System#getProperties()
I'm using
boolean android = "The Android Project".equals(System.getProperty("java.specification.vendor"));
I use this in my processing sketch to determine in which mode I'm running i.e. where I'm running it.
enum Mode {
java, android
}
Mode getMode() {
return System.getProperty("java.runtime.name").equals("Android Runtime") ? Mode.android : Mode.java;
}
if (getMode() == Mode.java){
// do something
// eg: do something that android can't handle
} else {
// do android stuff
// eg: scale the sketch by 2 to improve visibility
}

Categories

Resources