【问题标题】:Programmatically getting the MAC of an Android device以编程方式获取 Android 设备的 MAC
【发布时间】:2012-07-27 04:48:48
【问题描述】:

我需要使用 Java 获取我的 android 设备的 MAC 地址。我在网上搜索过,但没有找到任何有用的东西。

【问题讨论】:

标签: java android mac-address


【解决方案1】:

我知道这是一个非常古老的问题,但还有另一种方法可以做到这一点。下面的代码可以编译,但我还没有尝试过。 您可以编写一些 C 代码并使用 JNI(Java Native Interface)来获取 MAC 地址。 这是示例主要活动代码:

package com.example.getmymac;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class GetMyMacActivity extends AppCompatActivity {
    static { // here we are importing native library.
        // name of the library is libnet-utils.so, in cmake and java code
        // we just use name "net-utils".
        System.loadLibrary("net-utils");
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_screen);

        // some debug text and a TextView.
        Log.d(NetUtilsActivity.class.getSimpleName(), "Starting app...");
        TextView text = findViewById(R.id.sample_text);

        // the get_mac_addr native function, implemented in C code.
        byte[] macArr = get_mac_addr(null);
        // since it is a byte array, we format it and convert to string.
        String val = String.format("%02x:%02x:%02x:%02x:%02x:%02x",
                macArr[0], macArr[1], macArr[2],
                macArr[3], macArr[4], macArr[5]);
        // print it to log and TextView.
        Log.d(NetUtilsActivity.class.getSimpleName(), val);
        text.setText(val);
    }

    // here is the prototype of the native function.
    // use native keyword to indicate it is a native function,
    // implemented in C code.
    private native byte[] get_mac_addr(String interface_name);
}

还有布局文件,main_screen.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/sample_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

清单文件,我不知道要添加什么权限,所以我添加了一些。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.getmymac">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".GetMyMacActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

get_mac_addr 函数的 C 实现。

/* length of array that MAC address is stored. */
#define MAC_ARR_LEN 6

#define BUF_SIZE 256

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define ERROR_IOCTL 1
#define ERROR_SOCKT 2

static jboolean
cstr_eq_jstr(JNIEnv *env, const char *cstr, jstring jstr) {
    /* see [this](https://stackoverflow.com/a/38204842) */

    jstring cstr_as_jstr = (*env)->NewStringUTF(env, cstr);
    jclass cls = (*env)->GetObjectClass(env, jstr);
    jmethodID method_id = (*env)->GetMethodID(env, cls, "equals", "(Ljava/lang/Object;)Z");
    jboolean equal = (*env)->CallBooleanMethod(env, jstr, method_id, cstr_as_jstr);
    return equal;
}

static void
get_mac_by_ifname(jchar *ifname, JNIEnv *env, jbyteArray arr, int *error) {
    /* see [this](https://stackoverflow.com/a/1779758) */

    struct ifreq ir;
    struct ifconf ic;
    char buf[BUF_SIZE];
    int ret = 0, sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

    if (sock == -1) {
        *error = ERROR_SOCKT;
        return;
    }

    ic.ifc_len = BUF_SIZE;
    ic.ifc_buf = buf;

    ret = ioctl(sock, SIOCGIFCONF, &ic);
    if (ret) {
        *error = ERROR_IOCTL;
        goto err_cleanup;
    }

    struct ifreq *it = ic.ifc_req; /* iterator */
    struct ifreq *end = it + (ic.ifc_len / sizeof(struct ifreq));

    int found = 0; /* found interface named `ifname' */

    /* while we find an interface named `ifname' or arrive end */
    while (it < end && found == 0) {
        strcpy(ir.ifr_name, it->ifr_name);
        ret = ioctl(sock, SIOCGIFFLAGS, &ir);
        if (ret == 0) {
            if (!(ir.ifr_flags & IFF_LOOPBACK)) {
                ret = ioctl(sock, SIOCGIFHWADDR, &ir);
                if (ret) {
                    *error = ERROR_IOCTL;
                    goto err_cleanup;
                }

                if (ifname != NULL) {
                    if (cstr_eq_jstr(env, ir.ifr_name, ifname)) {
                        found = 1;
                    }
                }
            }
        } else {
            *error = ERROR_IOCTL;
            goto err_cleanup;
        }
        ++it;
    }

    /* copy the MAC address to byte array */
    (*env)->SetByteArrayRegion(env, arr, 0, 6, ir.ifr_hwaddr.sa_data);
    /* cleanup, close the socket connection */
    err_cleanup: close(sock);
}

JNIEXPORT jbyteArray JNICALL
Java_com_example_getmymac_GetMyMacActivity_get_1mac_1addr(JNIEnv *env, jobject thiz,
                                                          jstring interface_name) {
    /* first, allocate space for the MAC address. */
    jbyteArray mac_addr = (*env)->NewByteArray(env, MAC_ARR_LEN);
    int error = 0;

    /* then just call `get_mac_by_ifname' function */
    get_mac_by_ifname(interface_name, env, mac_addr, &error);

    return mac_addr;
}

最后是 CMakeLists.txt 文件

cmake_minimum_required(VERSION 3.4.1)
add_library(net-utils SHARED src/main/cpp/net-utils.c)
target_link_libraries(net-utils android log)

【讨论】:

  • 我在 Android 30 上试过这个,它返回全零。
【解决方案2】:

ip link | grep -A1 wlan0 命令适用于来自How to determine wifi hardware address in Termux 的Android 9

【讨论】:

    【解决方案3】:

    我想我刚刚找到了一种无需 LOCATION 权限即可读取 MAC 地址的方法:运行 ip link 并解析其输出。 (你可以通过查看这个二进制文件的源代码来做类似的事情)

    【讨论】:

      【解决方案4】:

      使用这个简单的方法

      WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
                  String WLANMAC = wm.getConnectionInfo().getMacAddress();
      

      【讨论】:

        【解决方案5】:

        我从http://robinhenniges.com/en/android6-get-mac-address-programmatically 创建了这个解决方案,它对我有用!希望有所帮助!

        public static String getMacAddr() {
            try {
                List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
                for (NetworkInterface nif : all) {
                    if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
        
                    byte[] macBytes = nif.getHardwareAddress();
                    if (macBytes == null) {
                        return "";
                    }
        
                    StringBuilder res1 = new StringBuilder();
                    for (byte b : macBytes) {
                        String hex = Integer.toHexString(b & 0xFF);
                        if (hex.length() == 1)
                            hex = "0".concat(hex);
                        res1.append(hex.concat(":"));
                    }
        
                    if (res1.length() > 0) {
                        res1.deleteCharAt(res1.length() - 1);
                    }
                    return res1.toString();
                }
            } catch (Exception ex) {
            }
            return "";
        }
        

        【讨论】:

        • 我想这是因为我们需要删除最后一个“:”字符。这段代码已经有 2 年历史了,可能不是最好的方法,你应该优化它
        【解决方案6】:

        它与棉花糖一起工作

        package com.keshav.fetchmacaddress;
        
        import android.support.v7.app.AppCompatActivity;
        import android.os.Bundle;
        import android.util.Log;
        
        import java.net.InetAddress;
        import java.net.NetworkInterface;
        import java.net.SocketException;
        import java.net.UnknownHostException;
        import java.util.Collections;
        import java.util.List;
        
        public class MainActivity extends AppCompatActivity {
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        
                Log.e("keshav","getMacAddr -> " +getMacAddr());
            }
        
            public static String getMacAddr() {
                try {
                    List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
                    for (NetworkInterface nif : all) {
                        if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
        
                        byte[] macBytes = nif.getHardwareAddress();
                        if (macBytes == null) {
                            return "";
                        }
        
                        StringBuilder res1 = new StringBuilder();
                        for (byte b : macBytes) {
                            res1.append(Integer.toHexString(b & 0xFF) + ":");
                        }
        
                        if (res1.length() > 0) {
                            res1.deleteCharAt(res1.length() - 1);
                        }
                        return res1.toString();
                    }
                } catch (Exception ex) {
                    //handle exception
                }
                return "";
            }
        }
        

        【讨论】:

        • 感谢卡迪尔侯赛因
        【解决方案7】:

        正如评论中已经指出的那样,可以通过WifiManager 接收 MAC 地址。

        WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiInfo info = manager.getConnectionInfo();
        String address = info.getMacAddress();
        

        也不要忘记将适当的权限添加到您的AndroidManifest.xml

        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
        

        请参考Android 6.0 Changes

        为了向用户提供更好的数据保护,从本版本开始,Android 移除了对使用 Wi-Fi 和蓝牙 API 的应用程序的设备本地硬件标识符的编程访问。 WifiInfo.getMacAddress() 和 BluetoothAdapter.getAddress() 方法现在返回一个常量值 02:00:00:00:00:00。

        要通过蓝牙和 Wi-Fi 扫描访问附近外部设备的硬件标识符,您的应用现在必须具有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限。

        【讨论】:

        • 也只是一个说明,有时因为设备上的wifi关闭而无法提取mac地址
        • 链接的博客还解释了如何在不假设网络接口使用 WiFi 连接的情况下以更通用的方式查找此 MAC 地址。
        • 记得使用上下文调用getSystemService。
        • 这非常适合使用 Wifi 的 Android 手机和平板电脑,但我正在尝试在可以使用 Wifi 或以太网的旧 Gingerbread Android 平板电脑上获取以太网 MAC 地址。关于如何检查以太网 MAC 地址的任何想法?谢谢。
        • @sbrichards 关闭 WiFi 是什么意思?
        【解决方案8】:
        public static String getMacAddr() {
            try {
                List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
                for (NetworkInterface nif : all) {
                    if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
        
                    byte[] macBytes = nif.getHardwareAddress();
                    if (macBytes == null) {
                        return "";
                    }
        
                    StringBuilder res1 = new StringBuilder();
                    for (byte b : macBytes) {
                        res1.append(String.format("%02X:",b));
                    }
        
                    if (res1.length() > 0) {
                        res1.deleteCharAt(res1.length() - 1);
                    }
                    return res1.toString();
                }
            } catch (Exception ex) {
            }
            return "02:00:00:00:00:00";
        }
        

        【讨论】:

        • 在 Android 7.1 上一直显示“02:00:00:00:00:00”。
        • 必须在物理设备上测试,而不是在模拟器或虚拟设备上测试
        • 它仍然有效。不要忘记在 Manifest 文件中授予 Internet 权限。
        • 它不再适用于 android marshmallow 及更高版本,因为它将返回“02:00:00:00:00:00”的值
        • 它有效。我已经使用此代码很长时间了。它仍然适用于 Android Q。
        【解决方案9】:

        您无法再获取安卓设备的硬件 MAC 地址。 WifiInfo.getMacAddress() 和 BluetoothAdapter.getAddress() 方法将返回 02:00:00:00:00:00。此限制是在 Android 6.0 中引入的。

        但是 Rob Anderson 找到了一个适用于 https://stackoverflow.com/a/35830358

        的解决方案

        【讨论】:

          【解决方案10】:

          通过WifiInfo.getMacAddress() 获取 MAC 地址在 Marshmallow 及更高版本上不起作用,它已被禁用并将返回the constant value of 02:00:00:00:00:00

          【讨论】:

          • 有什么选择?
          • @SameerThigale 取决于您要实现的目标。这背后的想法是您可能不应该尝试获取 MAC 地址。
          • 我不知道为什么,但我在链接的 api 文档中找不到弃用的注释。也许他们改变了主意?
          • @DBX12 该方法本身没有被标记为已弃用,尽管它没有记录在案。第二个链接指向有关它的官方说明。
          【解决方案11】:

          取自 Android 资源 here。这是在系统设置应用程序中显示您的 MAC 地址的实际代码。

          private void refreshWifiInfo() {
              WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
          
              Preference wifiMacAddressPref = findPreference(KEY_MAC_ADDRESS);
              String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
              wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress
                      : getActivity().getString(R.string.status_unavailable));
          
              Preference wifiIpAddressPref = findPreference(KEY_CURRENT_IP_ADDRESS);
              String ipAddress = Utils.getWifiIpAddresses(getActivity());
              wifiIpAddressPref.setSummary(ipAddress == null ?
                      getActivity().getString(R.string.status_unavailable) : ipAddress);
          }
          

          【讨论】:

          • 我应该如何在非活动类或片段中访问它?
          • 您将需要一个上下文来获取WifiManager(即WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);)。
          • 如果它尝试这个代码我得到02:00:00:00:00:00 mac 地址而不是实际的 wifi mac id
          【解决方案12】:

          可以获取mac地址:

          WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
          WifiInfo wInfo = wifiManager.getConnectionInfo();
          String mac = wInfo.getMacAddress();
          

          在 Menifest.xml 中设置权限

          <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
          

          【讨论】:

          • 问题是关于获取android设备的mac,而不是wifi路由器。
          【解决方案13】:
          <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
          
          public String getMacAddress(Context context) {
              WifiManager wimanager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
              String macAddress = wimanager.getConnectionInfo().getMacAddress();
              if (macAddress == null) {
                  macAddress = "Device don't have mac address or wi-fi is disabled";
              }
              return macAddress;
          }
          

          有其他方式here

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-01-17
          • 2013-01-27
          • 1970-01-01
          • 2011-02-15
          • 2018-10-07
          • 1970-01-01
          • 2012-06-05
          • 1970-01-01
          相关资源
          最近更新 更多