AndroidはJNIでMACアドレスを取得する(Android 6.0以上に適合)


最近のプロジェクトでは、C++レイヤで暗号化し、soにコンパイルする必要があると遭遇しました.MACアドレスはデバイスの一意性を識別できることを知っている.だから、C++層でMACアドレスを取得する必要があります.ここではJNIを使ってプログラミングする必要があります.あまり言わないで、どのように取得するかを見てみましょう.
その前に、権限の追加を忘れないでください.
android:name="android.permission.INTERNET" />
android:name="android.permission.READ_PHONE_STATE" />
android:name="android.permission.ACCESS_WIFI_STATE" />

まず、javaでどのように取得されたかを見てみましょう.Android6.0以前のメソッドは6.0以降では成功しませんでした.最新の取得方法を直接使用しますコードは簡単で、静的メソッドgetByNameでNetworkInterfaceインスタンスを取得し、getHardwareAddress()でbyte[]配列を取得します.ここで取得したのは16進数配列で、変換が必要です.
/**
     *     MAC  
     * */
    public static String getMacAddress() {
 /*  mac            android 6.0   ,          ,          "02:00:00:00:00:00"     macgoogel              getSYstemService(Context.WIFI_SERVICE)     mac*/
        //        String macAddress= "";
//        WifiManager wifiManager = (WifiManager) MyApp.getContext().getSystemService(Context.WIFI_SERVICE);
//        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
//        macAddress = wifiInfo.getMacAddress();
//        return macAddress;

        String macAddress = null;
        StringBuffer buf = new StringBuffer();
        NetworkInterface networkInterface = null;
        try {
            networkInterface = NetworkInterface.getByName("eth1");
            if (networkInterface == null) {
                networkInterface = NetworkInterface.getByName("wlan0");
            }
            if (networkInterface == null) {
                return "02:00:00:00:00:02";
            }
            byte[] addr = networkInterface.getHardwareAddress();
            for (byte b : addr) {
                buf.append(String.format("%02X:", b));
            }
            if (buf.length() > 0) {
                buf.deleteCharAt(buf.length() - 1);
            }
            macAddress = buf.toString();
        } catch (SocketException e) {
            e.printStackTrace();
            return "02:00:00:00:00:02";
        }
        return macAddress;
    }
そしてこの方法に従ってJNIで実現する
//  JNI  java  NetworkInterface 
jclass cls_networkInterface = env->FindClass("java/net/NetworkInterface");
if (cls_networkInterface == 0) {
    return env->NewStringUTF("");
}
//  getByName  
jmethodID jmethodID1 = env->GetStaticMethodID(cls_networkInterface, "getByName", "(Ljava/lang/String;)Ljava/net/NetworkInterface;");
if (jmethodID1 == 0)
    return env->NewStringUTF("");
std::string ss = "wlan0";
jstring jss2 = env->NewStringUTF(ss.c_str());
//  getByname    NetworkInterface   
jobject jobject1 = env->CallStaticObjectMethod(cls_networkInterface, jmethodID1, jss2);
//  getHardAddress  
jmethodID getHardwareAddress = env->GetMethodID(cls_networkInterface, "getHardwareAddress", "()[B");
if (getHardwareAddress == 0)
    return env->NewStringUTF("");
//  getHardAddress    MAC   byte[]  
jbyteArray jbyte1 = (jbyteArray)env->CallObjectMethod(jobject1, getHardwareAddress);
//          byte[]     char           
jbyte * olddata = (jbyte*)env->GetByteArrayElements(jbyte1, 0);
jsize  oldsize = env->GetArrayLength(jbyte1);
// BYTE     #define BYTE unsigned char
BYTE* bytearr = (BYTE*)olddata;
int len = (int)oldsize;

char* data = (char*)env->GetByteArrayElements(jbyte1, 0);
char *temp = new char[len*2 + 1];
memset(temp,0,len*2 +1);
for (int i = 0; i < len; i++) {
    char * buffer = new char[2];
    memset(buffer,2,0);
    sprintf(buffer, "%02X", data[i]);
    memcpy(temp+i*2, buffer, 2);
    delete[] (buffer);
}
jstring jMac = charTojstring(env, temp);
delete[] temp;
return jMac;

ここでBYTEはマクロ定義でcppファイルに加算
#define BYTE unsigned char
charTojstringメソッドは次のとおりです.
jstring charTojstring(JNIEnv* env, const char* pat) {
    //  java String  strClass
    jclass strClass = (env)->FindClass("java/lang/String");
    //  String(byte[],String)    ,     byte[]        String
    jmethodID ctorID = (env)->GetMethodID(strClass, "", "([BLjava/lang/String;)V");
    //  byte  
    jbyteArray bytes = (env)->NewByteArray(strlen(pat));
    // char*    byte  
    (env)->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*) pat);
    //   String,       ,  byte     String    
    jstring encoding = (env)->NewStringUTF("GB2312");
    // byte     java String,   
    return (jstring) (env)->NewObject(strClass, ctorID, bytes, encoding);
}

主な難点は、データの変換方法です.JNIはjava反射法のような一連の方法でjavaのしたことを完成させ、javaの呼び出しを行う.具体的なパラメータ変換はネット上にたくさんありますが、ここではリストしません.これにより、デバイスのMACアドレスが取得されます.もちろん、一般的にはjavaレイヤに戻る必要はありません(javaは取得できますが、なぜcレイヤで取得するのが面倒なのか、私が病気でない限り戻ります.)20は、暗号化などのMACアドレスをJNIレイヤで直接操作します.
文章はここまでで、みんなはjavaの多くの方法に対してJNI呼び出しを行うことができて、システムのクラスのほかに、私达もクラスをカスタマイズすることができて、もしコードに対して暗号化する必要があるならば、他の人に简単な反コンパイルをさせたくなくて、この技を使うことができて、结局soはやはりとても安全です.