Skip to content

Instantly share code, notes, and snippets.

@DmitrySkiba
Created June 9, 2011 17:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save DmitrySkiba/1017293 to your computer and use it in GitHub Desktop.
Save DmitrySkiba/1017293 to your computer and use it in GitHub Desktop.
JNIpp: getting IMEI from native code on Android
/* 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 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
@firexel
Copy link

firexel commented Sep 2, 2013

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment