Nhận MAC của thiết bị Android theo chương trình


91

Tôi cần lấy địa chỉ MAC của thiết bị Android của mình bằng Java. Tôi đã tìm kiếm trực tuyến, nhưng tôi không tìm thấy bất cứ điều gì hữu ích.





Vui lòng kiểm tra giải pháp này, nó phù hợp với tôi stackoverflow.com/questions/31329733/…
Gorio

Từ android M, api này không được dùng nữa, hãy sử dụng cái này ngay bây giờ: stackoverflow.com/questions/31329733/…
Ehud

Câu trả lời:


114

Như đã được chỉ ra trong nhận xét, địa chỉ MAC có thể được nhận qua WifiManager .

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

Cũng đừng quên thêm các quyền thích hợp vào AndroidManifest.xml

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

Vui lòng tham khảo các Thay đổi của Android 6.0 .

Để cung cấp cho người dùng khả năng bảo vệ dữ liệu tốt hơn, bắt đầu từ phiên bản này, Android sẽ xóa quyền truy cập có lập trình vào mã nhận dạng phần cứng cục bộ của thiết bị đối với các ứng dụng sử dụng API Wi-Fi và Bluetooth. Các phương thức WifiInfo.getMacAddress () và BluetoothAdapter.getAddress () hiện trả về một giá trị không đổi là 02: 00: 00: 00: 00: 00.

Để truy cập số nhận dạng phần cứng của các thiết bị bên ngoài lân cận qua Bluetooth và quét Wi-Fi, ứng dụng của bạn hiện phải có quyền ACCESS_FINE_LOCATION hoặc ACCESS_COARSE_LOCATION.


11
Cũng chỉ là một lưu ý, đôi khi địa chỉ mac không thể được kéo bởi vì wifi tắt trên thiết bị
sbrichards

3
Blog được liên kết cũng giải thích cách tìm địa chỉ MAC này theo cách tổng quát hơn mà không giả sử giao diện mạng sử dụng kết nối WiFi.
Stephen C,

Hãy nhớ sử dụng ngữ cảnh để gọi getSystemService.
Tito Leiva

Điều này rất tốt cho điện thoại và máy tính bảng Android sử dụng Wifi, nhưng tôi đang cố lấy địa chỉ MAC Ethernet trên máy tính bảng Android Gingerbread cũ có thể sử dụng Wifi hoặc Ethernet. bất kỳ suy nghĩ về cách kiểm tra địa chỉ MAC Ethernet? Cảm ơn.
Seth

@sbrichards Ý bạn là gì khi WiFi bị tắt?
peterchaula

33

Việc lấy địa chỉ MAC thông qua WifiInfo.getMacAddress()sẽ không hoạt động trên Marshmallow trở lên, nó đã bị vô hiệu hóa và sẽ trả về giá trị không đổi là02:00:00:00:00:00 .


3
Giải pháp thay thế là gì?
Sam

2
@SameerThigale Phụ thuộc vào những gì bạn đang cố gắng đạt được. Ý tưởng đằng sau điều này là bạn có thể không nên cố lấy địa chỉ MAC.
minipif

Tôi không chắc tại sao, nhưng tôi không thể tìm thấy ghi chú không dùng nữa trong tài liệu api được liên kết. Có lẽ họ đã thay đổi ý định về điều này?
DBX12

1
@ DBX12 Bản thân phương pháp này không được đánh dấu là không dùng nữa, mặc dù nó không được ghi lại. Liên kết thứ hai trỏ đến một ghi chú chính thức về nó.
minipif

24
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";
}

2
Nó liên tục hiển thị cho tôi "02: 00: 00: 00: 00: 00" trên Android 7.1.
nhà phát triển android

Nó phải được kiểm tra trên thiết bị Vật lý chứ không phải là trình mô phỏng hoặc thiết bị ảo
pm

Cách tiếp cận này có hoạt động xung quanh vẫn hoạt động không? hay nó đã được vá / sửa ở phía hệ điều hành?
CasualT

1
Nó vẫn hoạt động. Đừng quên cấp quyền truy cập internet trong tệp Manifest.
pm dubey

1
Nó không còn hoạt động trên android marshmallow trở lên vì nó sẽ trả về giá trị "02: 00: 00: 00: 00: 00"
SweArmy

11
<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;
}

có những con đường khác ở đây


Sẽ macAddressbao giờ null?
Max Heiber

tham số nào cần chuyển dưới dạng ngữ cảnh trong khi gọi hàm?
Donal

@Donal bạn có nghĩa là Context context? nếu có, bất kỳ bối cảnh nào sẽ hoạt động. developer.android.com/reference/android/content/…
ademar111190

11

Tôi đã thành lập giải pháp này từ http://robinhenniges.com/en/android6-get-mac-address-programmatically và nó phù hợp với tôi! Hy vọng sẽ giúp!

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 "";
}

Tôi cho rằng đó là vì chúng ta cần xóa ký tự “:” cuối cùng. Mã này được 2 tuổi và có lẽ itsn't cách tốt nhất để làm điều đó, bạn nên tối ưu hóa nó
Tiziano Bruschetta

7

Hoạt động của nó với Marshmallow

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 "";
    }
}

Cảm ơn Qadir Hussain
Keshav Gera

3

Bạn có thể lấy địa chỉ mac:

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

Đặt quyền trong Menifest.xml

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

Câu hỏi là về việc nhận mac của thiết bị Android, không phải của bộ định tuyến wifi.
hina abbasi

3

Bạn không thể lấy địa chỉ MAC phần cứng của thiết bị Android nữa. Các phương thức WifiInfo.getMacAddress () và BluetoothAdapter.getAddress () sẽ trả về 02: 00: 00: 00: 00: 00. Hạn chế này đã được giới thiệu trong Android 6.0.

Nhưng Rob Anderson đã tìm thấy một giải pháp đang hoạt động cho <Marshmallow: https://stackoverflow.com/a/35830358


2

Lấy từ các nguồn Android tại đây . Đây là mã thực tế hiển thị ĐỊA CHỈ MAC của bạn trong ứng dụng cài đặt của hệ thống.

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);
}

làm cách nào để truy cập vào phần này trong lớp hoặc phân đoạn không hoạt động?
Săn

Bạn sẽ cần một ngữ cảnh để có được WifiManager(tức là WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);).
fernandohur

5
nếu nó thử mã này tôi đang nhận được 02:00:00:00:00:00địa chỉ mac không phải là thực tế wifi mac id
Hunt

2

Sử dụng phương pháp đơn giản này

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

0

Tôi biết đây là một câu hỏi rất cũ nhưng có một phương pháp nữa để làm điều này. Dưới đây biên dịch mã nhưng tôi chưa thử. Bạn có thể viết một số mã C và sử dụng JNI (Java Native Interface) để lấy địa chỉ MAC. Đây là ví dụ về mã hoạt động chính:

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);
}

Và tệp bố cục, 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>

Tệp kê khai, tôi không biết phải thêm quyền gì nên tôi đã thêm một số.

<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>

C thực hiện hàm get_mac_addr.

/* 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;
}

Và cuối cùng, tệp 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)


-3

Tôi nghĩ rằng tôi vừa tìm thấy một cách để đọc địa chỉ MAC mà không cần sự cho phép của LOCATION: Chạy ip linkvà phân tích cú pháp đầu ra của nó. (bạn có thể làm điều tương tự bằng cách xem mã nguồn của tệp nhị phân này)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.