public
Last active

JNIpp: getting IMEI from native code on Android

  • Download Gist
gistfile1.cpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
/* There is no native way to get IMEI, so we have to call
* Java classes through JNI.
*
* But fear not: JNIpp (github.com/DmitrySkiba/itoa-jnipp) makes
* this task much easier.
*
* To get IMEI we need to perform the following calls:
*
* TelephonyManager telephony=(TelephonyManager)
* context.getSystemService(Context.TELEPHONY_SERVICE);
* String id=telephony.getDeviceId();
*/
 
/* This is 'quick'n'dirty' way of doing the task. JNIpp was designed for
* creating wrapper classes, and is not very well suited for ad-hoc
* calls. See next file for 'proper' way.
*/
 
/* There will little explanations, see dmitryskiba.github.com/itoa-jnipp/
* for help and examples.
*/
 
/* Function GetDeviceId() is at the end.
*/
 
/**************************************/
 
/* First, implement GetSystemService() function to perform
* Context.getSystemService().
*/
 
#define JB_CURRENT_CLASS Context
 
JB_DEFINE_ACCESSOR(
"android/content/Context"
,
NoFields
,
Methods
(
GetSysSvc,
"getSystemService","(Ljava/lang/String;)Ljava/lang/Object;"
)
)
 
static java::PObject GetSystemService(java::PObject context,const char* serviceName) {
return java::PObject::Wrap(
JB_CALL(ObjectMethod,context,GetSysSvc,java::PString::New(serviceName))
);
}
 
#undef JB_CURRENT_CLASS
 
 
/**************************************/
 
/* Then implement TelephonyManager.getDeviceId().
*/
 
#define JB_CURRENT_CLASS TelephonyManager
 
JB_DEFINE_ACCESSOR(
"android/telephony/TelephonyManager"
,
NoFields
,
Methods
(
GetDeviceId,
"getDeviceId","()Ljava/lang/String;"
)
)
 
static java::PString GetDeviceId(java::PObject telephony) {
return java::PString::Wrap(
JB_CALL(ObjectMethod,telephony,GetDeviceId)
);
}
 
#undef JB_CURRENT_CLASS
 
 
/**************************************/
 
/* And finally, put it all together.
* 'contextObject' is a Context instance, typically an Activity
* (if you have NativeActivity object, it is nativeActivity->clazz).
*/
void GetDeviceId(jobject contextObject) {
java::PObject context=java::PObject::Wrap(contextObject);
java::PObject telephony=GetSystemService(context,"phone");
if (!telephony) {
// Oops, no service.
} else {
java::PString idString=GetDeviceId(telephony);
if (!idString) {
// We've got NULL
} else {
const char* id=idString->GetUTF();
// Work with id.
}
}
}
gistfile2.cpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
/* This correct (as per JNIpp) way of working with Java classes:
* you create wrappers for all classes you are interested in
* and then your code reads much close to the Java original Java.
*/
 
void GetDeviceId(jobject contextObject) {
PContext context=PContext::Wrap(contextObject);
PTelephonyManager telephony=java::Cast<TelephonyManager>(
context->GetSystemService(Context::TELEPHONY_SERVICE));
if (telephony) {
java::PString id=telephony->GetDeviceId();
if (id) {
const char* idUTF=id->GetUTF();
// Work with id.
}
}
}
 
/**********************************************************/
 
/* First, declare wrapper classes. This should go in a header file.
*/
 
class Context: public java::Object {
JB_WRAPPER_CLASS(Context);
public:
static const char* const TELEPHONY_SERVICE;
public:
Context(const jni::LObject& context);
java::PObject GetSystemService(const char* name) const;
};
typedef java::ObjectPointer<Context> PContext;
 
 
class TelephonyManager: public java::Object {
JB_WRAPPER_CLASS(TelephonyManager);
public:
TelephonyManager(const jni::LObject& telephony);
java::PString GetDeviceId() const;
};
typedef java::ObjectPointer<TelephonyManager> PTelephonyManager;
 
 
/**********************************************************/
 
/* Then implement wrapper classes. This should go in cpp file (or files).
*/
 
/**************************************/
 
#define JB_CURRENT_CLASS Context
 
JB_DEFINE_WRAPPER_CLASS(
"android/content/Context"
,
NoFields
,
Methods
(
GetSysSvc,
"getSystemService","(Ljava/lang/String;)Ljava/lang/Object;"
)
)
 
const char* const Context::TELEPHONY_SERVICE="phone";
 
Context::Context(const jni::LObject& context):
java::Object(context)
{
}
 
java::PObject Context::GetSystemService(const char* name) const {
return java::PObject::Wrap(
JB_CALL_THIS(ObjectMethod,GetSysSvc,java::PString::New(name))
);
}
 
#undef JB_CURRENT_CLASS
 
/**************************************/
 
#define JB_CURRENT_CLASS TelephonyManager
 
JB_DEFINE_WRAPPER_CLASS(
"android/telephony/TelephonyManager"
,
NoFields
,
Methods
(
GetDeviceId,
"getDeviceId","()Ljava/lang/String;"
)
)
 
TelephonyManager::TelephonyManager(const jni::LObject& telephony):
java::Object(telephony)
{
}
 
java::PString TelephonyManager::GetDeviceId() const {
return java::PString::Wrap(
JB_CALL_THIS(ObjectMethod,GetDeviceId)
);
}
 
#undef JB_CURRENT_CLASS

Just for a great justice. You, actually, can get IMEI from native witout JNI calls. See here.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.