Created
June 9, 2011 17:52
-
-
Save DmitrySkiba/1017293 to your computer and use it in GitHub Desktop.
JNIpp: getting IMEI from native code on Android
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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. | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just for a great justice. You, actually, can get IMEI from native witout JNI calls. See here.