Cree un punto de acceso con el Nexus 7

¿Cuál es el objetivo?

Cree un punto de acceso con un dispositivo Android (Nexus 7 en mi caso). El propósito final es conectar una tarjeta WiFly a esta red creada e intercambiar datos entre estos dispositivos.

Hardware:

  • Nexus 7 con la versión 4.2.2 de Android con raíces con la ROM CyanogenMod 10.1
  • Tarjeta WiFly: Escudo Arduino con la misma disposición que las tarjetas Zigbee que usan Wifi ( el producto )

Software:

Entendí que la versión 4.2.2 de Android no permite crear un punto de acceso (el servicio está deshabilitado mediante programación). Esta es la razón por la raíz de mi dispositivo con la ROM de CyanogenMod. Esta ROM habilita este servicio.

Google ha ocultado algunos métodos de la clase WifiManager . Específicamente, el método setWifiApEnabled . Esta es la razón por la que uso la reflexión para llamar a métodos en el código de abajo.

¡El código fuente es enorme! Concéntrese en el método createAccessPoint() . Elegí poner todo el código fuente para ayudar a la gente que quiere saber cómo hice todo esto.

 public class TestAccessPoint extends Activity { static final String TAG = "AP_TEST"; static final String SSID = "\"Awesome Access Point\""; static final String PSK = "\"helloworld\""; String numberOfClientsConnected; String wifiApEnable; String wifiApState; WifiConfiguration wifiApConfig; WifiManager wifiManager; WifiConfiguration wifiConfiguration; BroadcastReceiver receiver; BroadcastReceiver receiverWifiDisabled; TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.accesspoint_test); textView = (TextView) findViewById(R.id.textView); wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); wifiConfiguration = new WifiConfiguration(); if(wifiManager.isWifiEnabled()) { createAccessPoint(); } else { Log.d(TAG, "Set wifi Enable"); wifiManager.setWifiEnabled(true); receiverWifiDisabled = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); if ( wifiState == WifiManager.WIFI_STATE_ENABLED ) { Log.d(TAG, "Wifi enable"); createAccessPoint(); } } }; registerReceiver(receiverWifiDisabled, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); } final Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 1: textView.setText( wifiApEnable + "\n" + wifiApState + "\n" + "Nb of clients connected: " + numberOfClientsConnected + "\n" + "Wifi AP configuration: " + "\n" + wifiApConfig.toString() + "\n" + "WifiManager connection info: " + "\n" + wifiManager.getConnectionInfo().toString() + "DHCP state: " + wifiManager.getDhcpInfo().toString() ); break; } } }; Thread thread = new Thread(new Runnable() { boolean alive = true; @Override public void run() { while(alive) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } numberOfClientsConnected = numberOfClientsConnected(); wifiApEnable = isWifiApEnabled(); wifiApState = getWifiApState(); wifiApConfig = getWifiApConfiguration(); mHandler.sendMessage(mHandler.obtainMessage(1)); } } }); thread.start(); } @Override public void onDestroy() { super.onDestroy(); if(receiver != null) { unregisterReceiver(receiver); } if(receiverWifiDisabled != null) { unregisterReceiver(receiverWifiDisabled); } } protected void createAccessPoint() { // Check if the Wifi configuration already exists List<WifiConfiguration> list = wifiManager.getConfiguredNetworks(); int networkID = -1; if(list != null){ for(WifiConfiguration conf : list) { Log.d(TAG, "Network ID: " + String.valueOf(conf.networkId) + " ; Network SSID: " + conf.SSID); if(conf.SSID.equals(SSID)) { Log.d(TAG, "SSID found"); networkID = conf.networkId; wifiConfiguration = conf; break; } } } else Log.d(TAG, "List of WifiConfiguration is null"); // If the configuration exists, remove it to recreate it from scratch if(networkID != -1) { wifiManager.removeNetwork(networkID); } // Create a new WiFi configuration wifiConfiguration.SSID = SSID; wifiConfiguration.preSharedKey = PSK; wifiConfiguration.hiddenSSID = false; wifiConfiguration.status = WifiConfiguration.Status.ENABLED; wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); wifiConfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); wifiConfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); wifiConfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); wifiConfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); wifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // Catch Enumeration IpAssignment and ProxySettings from WifiConfiguration Enum ipAssignment = catchEnumIpAssignmentFromWifiConfiguration(); Enum proxySettings = catchEnumProxySettingsFromWifiConfiguration(); // Set IP address, gateway, DNS, etc try { Log.d(TAG, "Try to set IP, gateway and DNS"); setIpAssignment(ipAssignment, wifiConfiguration); Log.d(TAG, "IpAssignment: Ok"); setProxySettings(proxySettings, wifiConfiguration); Log.d(TAG, "ProxySettings: Ok"); setIpAddress(InetAddress.getByName("192.168.2.100"), 24, wifiConfiguration); Log.d(TAG, "IpAddress: Ok"); setGateway(InetAddress.getByName("192.168.2.1"), wifiConfiguration); Log.d(TAG, "Gateway: Ok"); setDNS(InetAddress.getByName("192.168.2.1"), wifiConfiguration); Log.d(TAG, "DNS: Ok"); } catch(Exception e) { e.printStackTrace(); } // Add this new configuration to the wpa_supplicant file networkID = wifiManager.addNetwork(wifiConfiguration); if(networkID != -1) Log.d(TAG, "Succeed to update the WiFi configuration: " + networkID); else Log.d(TAG, "Failed to update the WiFi configuration"); // Save the new configuration on the wpa_supplicant if(wifiManager.saveConfiguration()) Log.d(TAG, "Succeed to save the wpa_supplicant"); else Log.d(TAG, "Failed to save the wpa_supplicant"); // Set the Wifi disable to be able to start the Access Point Log.d(TAG, "Set wifi disable"); wifiManager.setWifiEnabled(false); receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); if ( wifiState == WifiManager.WIFI_STATE_DISABLED ) { Log.d(TAG, "Wifi disabled"); // When the Wifi is disable // Create the Access Point with the WiFi configuration try { Method m = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class); boolean succeed = (Boolean) m.invoke(wifiManager, wifiConfiguration, true); if(succeed) Log.d(TAG, "Succeed to set wifi AP"); else Log.d(TAG, "A problem occured while setting the wifi AP"); } catch (Exception e) { Log.e(TAG, "Failed to set wifi AP", e); } } } }; registerReceiver(receiver, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); } protected String getWifiApState() { try { Method m3 = wifiManager.getClass().getMethod("getWifiApState"); return "WiFi Ap State: " + String.valueOf(m3.invoke(wifiManager)); } catch (NoSuchMethodException e1) { e1.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } protected WifiConfiguration getWifiApConfiguration() { WifiConfiguration wifiConfiguration = null; try { Method m4 = wifiManager.getClass().getMethod("getWifiApConfiguration"); wifiConfiguration = (WifiConfiguration) m4.invoke(wifiManager); } catch (Exception e) { e.printStackTrace(); } return wifiConfiguration; } protected String isWifiApEnabled() { try { Method m = wifiManager.getClass().getMethod("isWifiApEnabled"); if((Boolean) m.invoke(wifiManager)) return "WiFiAP enabled"; else return "WiFiAP not enabled"; } catch (Exception e) { e.printStackTrace(); } return null; } protected String numberOfClientsConnected() { int macCount = 0; BufferedReader br = null; try { br = new BufferedReader(new FileReader("/proc/net/arp")); String line; while ((line = br.readLine()) != null) { String[] splitted = line.split(" +"); if (splitted != null && splitted.length >= 4) { String mac = splitted[3]; if (mac.matches("..:..:..:..:..:..")) { macCount++; } } } } catch (Exception e) { e.printStackTrace(); } finally { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } return String.valueOf(macCount); } @SuppressWarnings({ "unchecked", "rawtypes" }) protected Enum catchEnumIpAssignmentFromWifiConfiguration() { Enum DHCP = null; try { Class<Enum> enumIpAssignment = (Class<Enum>) Class.forName("android.net.wifi.WifiConfiguration$IpAssignment"); DHCP = Enum.valueOf(enumIpAssignment, "DHCP"); } catch (ClassNotFoundException e) { e.printStackTrace(); } return DHCP; } @SuppressWarnings({ "unchecked", "rawtypes" }) protected Enum catchEnumProxySettingsFromWifiConfiguration() { Enum ProxySet = null; try { Class<Enum> enumProxySettings = (Class<Enum>) Class.forName("android.net.wifi.WifiConfiguration$ProxySettings"); ProxySet = Enum.valueOf(enumProxySettings, "NONE"); } catch (ClassNotFoundException e) { e.printStackTrace(); } return ProxySet; } public static void setIpAssignment(Object assign , WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException { setEnumField(wifiConf, assign, "ipAssignment"); } public static void setProxySettings(Object assign , WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException { setEnumField(wifiConf, assign, "proxySettings"); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void setIpAddress(InetAddress addr, int prefixLength, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException, InstantiationException, InvocationTargetException { Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null) return; Class laClass = Class.forName("android.net.LinkAddress"); Constructor laConstructor = laClass.getConstructor(new Class[]{InetAddress.class, int.class}); Object linkAddress = laConstructor.newInstance(addr, prefixLength); ArrayList mLinkAddresses = (ArrayList)getDeclaredField(linkProperties, "mLinkAddresses"); mLinkAddresses.clear(); mLinkAddresses.add(linkAddress); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void setGateway(InetAddress gateway, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException { Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null)return; Class routeInfoClass = Class.forName("android.net.RouteInfo"); Constructor routeInfoConstructor = routeInfoClass.getConstructor(new Class[]{InetAddress.class}); Object routeInfo = routeInfoConstructor.newInstance(gateway); ArrayList mRoutes = (ArrayList)getDeclaredField(linkProperties, "mRoutes"); mRoutes.clear(); mRoutes.add(routeInfo); } @SuppressWarnings("unchecked") public static void setDNS(InetAddress dns, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException { Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null)return; ArrayList<InetAddress> mDnses = (ArrayList<InetAddress>)getDeclaredField(linkProperties, "mDnses"); mDnses.clear(); mDnses.add(dns); } public static Object getField(Object obj, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field f = obj.getClass().getField(name); Object out = f.get(obj); return out; } public static Object getDeclaredField(Object obj, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field f = obj.getClass().getDeclaredField(name); f.setAccessible(true); Object out = f.get(obj); return out; } public static void setEnumField(Object obj, Object value, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field f = obj.getClass().getField(name); f.set(obj, value); } } 

Este código funciona bien en mi Nexus 7. Crea un punto de acceso. Mi computadora portátil ve el enlace de la red esto: Introduzca aquí la descripción de la imagen

Me pide que ingrese la clave WPA. Necesito escribirlo envuelto con comillas si no funciona ( "helloworld" ).

Después de eso, mi portátil está conectado a la red, pero con el software Xirrus me di cuenta de que el módulo DHCP no da ninguna dirección IP.

Registros:

Tengo dos registros interesantes. Éste es cuando comienzo la aplicación:

 E/hostapd(): Configuration file: /data/misc/wifi/hostapd.conf E/hostapd(): HT (IEEE 802.11n) in 11b mode is not allowed, disabling HT capabilites I/hostapd(): rfkill: Cannot open RFKILL control device W/hostapd(): wlan0: Could not connect to kernel driver E/hostapd(): Using interface wlan0 with hwaddr 02:1a:11:fd:32:58 and ssid "\"Awesome Access Point\"" E/hostapd(): random: Cannot read from /dev/random: Try again I/hostapd(): random: Only 0/20 bytes of strong random data available from /dev/random I/hostapd(): random: Allow operation to proceed based on internal entropy 

Y éste es cuando conecto y desconecto mi computadora portátil de / al punto de acceso:

 I/hostapd(): wlan0: AP-STA-DISCONNECTED 00:27:10:ca:f0:80 I/hostapd(): wlan0: AP-STA-CONNECTED 00:27:10:ca:f0:80 

Preguntas:

  • Si usted piensa que estoy haciendo el camino equivocado, ¿podría decirme una mejor manera?
  • ¿Sabes por qué no recibí la dirección IP del módulo DHCP?
  • ¿Sabe que podría obtener más información / logs del módulo DHCP?

Gracias por tu apoyo.

Desafortunadamente, esto no es posible. La versión de existencias de Android ROM para Nexus 7 simplemente no tiene capacidad para crear puntos de acceso WiFi (está desactivada de forma predeterminada). La única manera razonable es root el dispositivo y cargar algunos ROM personalizado como CyanogenMod o algo así. CyanogenMod, por ejemplo, tiene la capacidad activada.

Siento decepcionarte, pero con firmware regular esto simplemente no es posible en absoluto.

  • ¿Cómo obtener la fuerza de conexión de los puntos de acceso Wifi?
  • Detectar si la conexión es wifi, 3G o EDGE en android?
  • Wifi triangulación de posición
  • Android / Java cómo saber el tipo de radio de wifi conectado
  • ¿Cómo mantiene Google actualizada su base de datos de geolocalización?
  • Supervisión del WiFi en el dispositivo Android
  • Java.net.SocketException: recvfrom falló: ECONNRESET (Conexión restablecida por pares) Más de WIFI
  • ANDROID: si WiFi está habilitado Y activo, inicia una intención
  • ¿Utiliza simultáneamente wifi y la interfaz 3G en Android?
  • ¿Cómo puedo ver si Wi-Fi está conectado en Android?
  • WiFi-Direct en JellyBean, WPA Suplicante desordenado
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.