最近在做一个Android的项目,程序还是只是一个试验品,但是关键点已经实现了,很多东西都是取自网络,现在分享一下:
【AndroidManifest.xml】:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.rengh.android.test" android:versionCode="1" android:versionName="1.0" >
<!-- 权限申请,第一个是NFC相关;然后是两个wifi和两个网络部分的权限,最后一个INTERNET是创建Socket需要的权限; --> <uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.rengh.android.test.MainActivity" android:label="@string/app_name" android:launchMode="singleTop" android:multiprocess="true" android:screenOrientation="portrait" android:stateNotNeeded="true" android:theme="@android:style/Theme.NoTitleBar" > <!-- portrait是限制为竖屏 --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
<!-- NDEF过滤;优先级高;用来注册,告诉系统能够处理扫描到的NDEF消息; --> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter>
</activity> </application> </manifest>
【MainActivity.java】处理NFC消息自动连接Wifi:
package com.rengh.android.test; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; import android.nfc.tech.NfcF; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.annotation.SuppressLint; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter.MalformedMimeTypeException; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; /* 继承 Activity类,继承Button.OnClickListener接口;*/ @SuppressLint({ "ShowToast", "HandlerLeak" }) public class MainActivity extends Activity implements Button.OnClickListener { /* * i*命名的整型变量代表主界面底部三个按钮被按下的次数; startActivityTime为时间值,单位毫秒; */ private int iAll = 0, iDefault = 0, iWhere = 0, startActivityTime = 2000; /* 定义各个界面的按钮; */ private Button btnAll, btnDefault, btnWhere, btnToOneActivity, btnOneToMainActivity, btnController, btnOneToSocketActivity; /* 定义主界面的三个TextView组件; */ private TextView textView_all, textView_default, textView_where; /* 定义当前设备的NfcAdapter; */ private NfcAdapter mNfcAdapter; /* */ private IntentFilter[] intentFiltersArray; /* */ private PendingIntent pendingIntent; /* */ private String[][] techListsArray; /* 定义从NFC标签读取到的字符串; */ private String nfcStr = null; private String fenGeFu = "\*"; /* * 定义Socket通信界面上的两个文本框,一个由用户输入信息, 一个显示服务器发送的消息; */ EditText inputText; TextView showText; /* 定义Socket通信界面上的一个按钮; */ Button btnSendText, btnToMainActivity; /* 定义Socket通信用到的Handler对象 */ Handler handler; /* 定义与服务器通信的子线程; */ ClientThread clientThread; int isWifiEnableStatue = 0, isWifiConnectedStatue = 0, nfcStatue; public static int socketStatue = 0; /** * 默认配置,测试时使用!!! */ String mSSID = "RhkySocket", mPASSWORD = "flamingoeda"; int mTYPE = 3; String deviceName = "Test-PC", ipAdress = "192.168.1.109"; int post = 30000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.start); /* * 在显示开始界面的情况下后台启动主界面, 直到过了startActivityTime时间后显示主界面; */ Handler x = new Handler(); x.postDelayed(new defaultStartApp(), startActivityTime); /* NFC相关; */ nfcManager(); /* 记录使用前wifi的状态; */ if (isWifiEnabled()) { isWifiEnableStatue = -1; } if (isWifiConnect()) { isWifiConnectedStatue = -1; } nfcStatue = 0; } /* 手动启动本程序调用,后台加载主界面; */ class defaultStartApp implements Runnable { public void run() { setContentView(R.layout.main); /* 设置layout_main.xml布局中的按钮和TextView控件; */ setMainActivityButtonAndTextView(); /* * 无NFC手机测试wifi自动连接使用,需要更改初始值为所用路由器无线信息; */ // AutoWifi(mSSID, mPASSWORD, mTYPE); // connectedSocketServer(deviceName, ipAdress, post); } } /* * nfc启动程序时调用,根据读取到的信息,后台运行连接wifi网络操作。 不后台运行的话会导致开始界面加载失败; */ class nfcStartApp implements Runnable { public void run() { sendConfigToAutoWifi(nfcStr); /* * 将无线网络名称str[0]、无线网络密码str[1]、 无线加密类型str[2],传递给AutoWifi方法; */ AutoWifi(mSSID, mPASSWORD, mTYPE); connectedSocketServer(deviceName, ipAdress, post); } } /* NFC标签读取; */ protected void nfcManager() { mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter == null) { Toast.makeText(this, "本设备不支持NFC功能", Toast.LENGTH_LONG).show(); } pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndef.addDataType("*/*"); } catch (MalformedMimeTypeException e) { throw new RuntimeException("fail", e); } intentFiltersArray = new IntentFilter[] { ndef, }; techListsArray = new String[][] { new String[] { NfcF.class.getName() } }; } @Override public void onResume() { super.onResume(); /* 启用nfc前台调度,保证程序开启状态下优先处理nfc包含的消息; */ if (mNfcAdapter != null) { mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray); } /* 能够将intent从外部传递到程序; */ if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction()) && (nfcStatue == 0)) { // 调用ndef消息的处理方法; processIntent(getIntent()); } } /* 有新的intent时调用; */ @Override public void onNewIntent(Intent intent) { /* 调用ndef消息的处理方法; */ processIntent(intent); } /* 定义ndef消息的处理方法; */ private void processIntent(Intent intent) { Parcelable[] rawMsgs = intent .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); NdefMessage msg = (NdefMessage) rawMsgs[0]; /* 提取NdefMessage消息的正文赋给字符串nfcStr; */ nfcStr = new String(msg.getRecords()[0].getPayload()); /* 后台调用nfcStartApp()方法,分析读到的消息并开始wifi连接; */ Handler x = new Handler(); x.postDelayed(new nfcStartApp(), startActivityTime); } /* 将nfc读到的消息分解后传递给AutoWifi方法进行自动连接; */ public void sendConfigToAutoWifi(String nfcStr) { /* * nfcStr = "Ren-gh_ren.gh.1989_3_A1_192.168.1.253_30000"; * 代表含义依次为:无线网络名称, 无线网络密码, 无线加密方式,设备名称,设备IP,设备端口号; * 将nfcStr字符串分解为多个字符串存到str字符串数组里; */ String str[]; str = nfcStr.split(fenGeFu); mSSID = str[0]; mPASSWORD = str[1]; mTYPE = Integer.valueOf(str[2]); deviceName = str[3]; ipAdress = str[4]; post = Integer.valueOf(str[5]); /* 清空nfcStr字符串 */ nfcStr = ""; ++nfcStatue; } /* 根据传递过来的三个无线网络参数连接wifi网络; */ private void AutoWifi(String ssid, String passwd, Integer type) { /* * 创建对象,打开wifi功能,等到wifi启动完成后将传递来的wifi网络添加进Network, * 然后等待连接诶成功后,传递设备名称,设备IP,设备端口号给connectedSocketServer方法, * 用来连接远程Socket服务器;Integer.valueOf(str[5])是将字符串转换为整型; */ /** * 定义AutoWifiConfig对象,通过该对象对wifi进行操作; WifiConfig myWifi = new * WifiConfig(this); 不能用作全局,不然会出现刷nfc连接wifi,连接到socket,再刷nfc时程序卡死的情况; */ WifiConfig myWifi = new WifiConfig(this); Boolean b; if (!isWifiEnabled()) { isWifiEnableStatue = 1; myWifi.openWifi(); do { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } b = isWifiEnabled(); } while (!b); } if (!isWifiConnect() || !myWifi.getSSID().equals(ssid)) { myWifi.addNetwork(myWifi.CreateWifiInfo(ssid, passwd, type)); do { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } b = isWifiConnect(); } while (!b); isWifiConnectedStatue = 1; } } /* 检查wifi是否可用;是则返回true; */ public boolean isWifiEnabled() { ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); NetworkInfo mWifi = connManager .getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isAvailable(); } /* 检查wifi是否连接成功;成功则返回true; */ public boolean isWifiConnect() { ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); NetworkInfo mWifi = connManager .getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); } /* 根据第二和第三个参数连接远程设备的Socket服务器; */ public void connectedSocketServer(String deviceName, String ipAdress, int post) { /* 加载socket通信的界面; */ setContentView(R.layout.socket); inputText = (EditText) findViewById(R.id.inputText); btnSendText = (Button) findViewById(R.id.btnSendText); showText = (TextView) findViewById(R.id.showText); btnToMainActivity = (Button) findViewById(R.id.btnSocketToMainActivity); btnToMainActivity.setOnClickListener(this); handler = new Handler() { @Override public void handleMessage(Message msg) { // 如果消息来自于子线程 if (msg.what == 0x123) { String recvString = msg.obj.toString(); if (!recvString.equals("0x123 close")) { // 将读取的内容最佳显示在文本框中 showText.append(recvString + " "); } } } }; clientThread = new ClientThread(handler, ipAdress, post); // 客户端启动ClientThread线程创建网络连接、读取来自服务器的数据 new Thread(clientThread).start(); btnSendText.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { /* * 当用户按下发送按钮后,判断用户输入的字符串不是空或 无意义的空格、TAB制表符的时候才进行处理; * String.trim().isEmpty()去掉前导空白和后导空白,再判断 * 是否为空;非空时将用户输入的数据封装成Message发送给子 线程的Handler; */ try { String sendString = inputText.getText().toString(); if (!sendString.trim().isEmpty()) { Message msg = new Message(); msg.what = 0x345; msg.obj = sendString; clientThread.recvHandler.sendMessage(msg); // 清空input文本框 inputText.setText(""); } } catch (Exception e) { e.printStackTrace(); } } }); } @Override public void onPause() { super.onPause(); if (mNfcAdapter != null) { /* 适时关闭前台调用,避免资源被占用; */ mNfcAdapter.disableForegroundDispatch(this); } } /* 设置TextView和按钮,为按钮监听事件, */ private void setMainActivityButtonAndTextView() { /* 所有展览点按钮监听; */ btnAll = (Button) findViewById(R.id.btnAll); btnAll.setOnClickListener(this); /* 推荐展览点 按钮监听; */ btnDefault = (Button) findViewById(R.id.btnDefault); btnDefault.setOnClickListener(this); /* 您的位置 按钮监听; */ btnWhere = (Button) findViewById(R.id.btnWhere); btnWhere.setOnClickListener(this); /* 下一页界面按钮监听; */ btnToOneActivity = (Button) findViewById(R.id.btnToOneActivity); btnToOneActivity.setOnClickListener(this); /* 关联界面布局中的文本显示框; */ textView_all = (TextView) findViewById(R.id.textView_all); textView_default = (TextView) findViewById(R.id.textView_default); textView_where = (TextView) findViewById(R.id.textView_where); } /* 关联one.xml界面布局中的“回到首页”按钮,设置监听事件; */ private void setOneActivityButtonAndTextView() { btnOneToMainActivity = (Button) findViewById(R.id.btnOneToMainActivity); btnOneToMainActivity.setOnClickListener(this); btnOneToSocketActivity = (Button) findViewById(R.id.btnOneToSocketActivity); btnOneToSocketActivity.setOnClickListener(this); btnController = (Button) findViewById(R.id.btnController); btnController.setOnClickListener(this); } /* 按钮点击事件处理方法; */ public void onClick(View v) { switch (v.getId()) { case R.id.btnAll: textView_all.setText("所有展品" + iAll++); break; case R.id.btnDefault: textView_default.setText("推荐展品" + iDefault++); break; case R.id.btnWhere: textView_where.setText("我的位置" + iWhere++); break; case R.id.btnToOneActivity: setContentView(R.layout.one); /* 设置one.xml布局中的按钮和TextView控件; */ setOneActivityButtonAndTextView(); break; case R.id.btnOneToMainActivity: setContentView(R.layout.main); /* 设置layout_main.xml布局中的按钮和TextView控件; */ setMainActivityButtonAndTextView(); break; case R.id.btnOneToSocketActivity: connectedSocketServer(deviceName, ipAdress, post); break; case R.id.btnController: break; case R.id.btnSocketToMainActivity: setContentView(R.layout.main); /* 设置layout_main.xml布局中的按钮和TextView控件; */ setMainActivityButtonAndTextView(); break; default: break; } } /* 返回键的监听事件; */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { /* * WifiConfig myWifi; myWifi = new WifiConfig(this); * if(isWifiEnableStatue == 1) { myWifi.removeWifiNetwork(); * myWifi.closeWifi(); } // 如果wifi已连接,断开wifi连接并退出 * if(isWifiConnectedStatue == 1) { myWifi.removeWifiNetwork(); * myWifi.disconnectWifi(); } */ finish(); return true; } return super.onKeyDown(keyCode, event); } }
【WifiConfig.java】一个别人封装的wifi操作的类,一开始加密网络连接不上,现在已经修改好,可以连接认证类型为WPA-PSK和WPA2-PSK的Wifi网络,无密码的依然可以连接,WEP认证方式的网络很少有人用,所以没有测试,代码如下:
package com.rengh.android.test; import java.util.List; import android.annotation.SuppressLint; import android.content.Context; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; @SuppressLint("UseValueOf") public class WifiConfig { // 定义WifiManager对象 private WifiManager mWifiManager; // 定义WifiInfo对象 private WifiInfo mWifiInfo; // 扫描出的网络连接列表 private List<ScanResult> mWifiList; // 网络连接列表 private List<WifiConfiguration> mWifiConfiguration; // 定义一个WifiLock WifiLock mWifiLock; // 构造器 public WifiConfig(Context context) { // 取得WifiManager对象 mWifiManager = (WifiManager) context .getSystemService(Context.WIFI_SERVICE); // 取得WifiInfo对象 mWifiInfo = mWifiManager.getConnectionInfo(); } // 打开WIFI public void openWifi() { if (!mWifiManager.isWifiEnabled()) { mWifiManager.setWifiEnabled(true); } } // 关闭WIFI public void closeWifi() { if (mWifiManager.isWifiEnabled()) { mWifiManager.setWifiEnabled(false); } } // 检查当前WIFI状态 public int checkState() { return mWifiManager.getWifiState(); } // 锁定WifiLock public void acquireWifiLock() { mWifiLock.acquire(); } // 解锁WifiLock public void releaseWifiLock() { // 判断时候锁定 if (mWifiLock.isHeld()) { mWifiLock.acquire(); } } // 创建一个WifiLock public void creatWifiLock() { mWifiLock = mWifiManager.createWifiLock("Test"); } // 得到配置好的网络 public List<WifiConfiguration> getConfiguration() { return mWifiConfiguration; } // 指定配置好的网络进行连接 public void connectConfiguration(int index) { // 索引大于配置好的网络索引返回 if (index > mWifiConfiguration.size()) { return; } // 连接配置好的指定ID的网络 mWifiManager.enableNetwork(mWifiConfiguration.get(index).networkId, true); } public void startScan() { mWifiManager.startScan(); // 得到扫描结果 mWifiList = mWifiManager.getScanResults(); // 得到配置好的网络连接 mWifiConfiguration = mWifiManager.getConfiguredNetworks(); } // 得到网络列表 public List<ScanResult> getWifiList() { return mWifiList; } // 查看扫描结果 public StringBuilder lookUpScan() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < mWifiList.size(); i++) { stringBuilder .append("Index_" + new Integer(i + 1).toString() + ":"); // 将ScanResult信息转换成一个字符串包 // 其中把包括:BSSID、SSID、capabilities、frequency、level stringBuilder.append((mWifiList.get(i)).toString()); stringBuilder.append("/n"); } return stringBuilder; } // 得到MAC地址 public String getMacAddress() { return (mWifiInfo == null) ? "NULL" : mWifiInfo.getMacAddress(); } // 得到接入点的SSID public String getSSID() { return (mWifiInfo == null) ? "NULL" : mWifiInfo.getSSID(); } // 得到IP地址 public int getIPAddress() { return (mWifiInfo == null) ? 0 : mWifiInfo.getIpAddress(); } // 得到连接的ID public int getNetworkId() { return (mWifiInfo == null) ? 0 : mWifiInfo.getNetworkId(); } public void removeWifiNetwork() { mWifiManager.removeNetwork(getNetworkId()); } // 得到WifiInfo的所有信息包 public String getWifiInfo() { return (mWifiInfo == null) ? "NULL" : mWifiInfo.toString(); } // 添加一个网络并连接 public void addNetwork(WifiConfiguration wcg) { int wcgID = mWifiManager.addNetwork(wcg); boolean b = mWifiManager.enableNetwork(wcgID, true); System.out.println("a--" + wcgID); System.out.println("b--" + b); } // 断开指定ID的网络 public void disconnectWifi(int netId) { mWifiManager.disableNetwork(netId); mWifiManager.disconnect(); } // 断开网络 public void disconnectWifi() { mWifiManager.disconnect(); } public WifiConfiguration CreateWifiInfo(String SSID, String Password, int Type) { WifiConfiguration config = new WifiConfiguration(); config.allowedAuthAlgorithms.clear(); config.allowedGroupCiphers.clear(); config.allowedKeyManagement.clear(); config.allowedPairwiseCiphers.clear(); config.allowedProtocols.clear(); config.SSID = """ + SSID + """; WifiConfiguration tempConfig = this.IsExsits(SSID); if (tempConfig != null) { mWifiManager.removeNetwork(tempConfig.networkId); } if (Type == 1) // WIFICIPHER_NOPASS { config.wepKeys[0] = ""; config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); config.wepTxKeyIndex = 0; } if (Type == 2) // WIFICIPHER_WEP { config.hiddenSSID = true; config.wepKeys[0] = """ + Password + """; config.allowedAuthAlgorithms .set(WifiConfiguration.AuthAlgorithm.SHARED); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); config.allowedGroupCiphers .set(WifiConfiguration.GroupCipher.WEP104); config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); config.wepTxKeyIndex = 0; } if (Type == 3) // WIFICIPHER_WPA { config.preSharedKey = """ + Password + """; config.hiddenSSID = true; config.allowedAuthAlgorithms .set(WifiConfiguration.AuthAlgorithm.OPEN); config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); config.allowedProtocols.set(WifiConfiguration.Protocol.WPA); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); config.allowedPairwiseCiphers .set(WifiConfiguration.PairwiseCipher.CCMP); config.status = WifiConfiguration.Status.ENABLED; config.allowedProtocols.set(WifiConfiguration.Protocol.RSN); } return config; } public WifiConfiguration IsExsits(String SSID) { List<WifiConfiguration> existingConfigs = mWifiManager .getConfiguredNetworks(); for (WifiConfiguration existingConfig : existingConfigs) { if (existingConfig.SSID.equals(""" + SSID + """)) { return existingConfig; } } return null; } }
【ClientThread.java】Socket通信的线程类,用来连接Socket服务器,发送和接受消息给UI线程:
package com.rengh.android.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.SocketException; import java.net.SocketTimeoutException; import android.annotation.SuppressLint; import android.os.Handler; import android.os.Looper; import android.os.Message; @SuppressLint("HandlerLeak") public class ClientThread implements Runnable { public static Socket s; // 定义向UI线程发送消息的Handler对象 private Handler handler; // 定义接收UI线程消息的Handler对象 Handler recvHandler; // 该线程处理的Socket对应的输入输出刘 BufferedReader br = null; OutputStream os = null; String strSsid; String ipAdress; Integer post; public ClientThread(Handler handler, String ipAdress, Integer post) { this.handler = handler; this.ipAdress = ipAdress; this.post = post; } public void run() { try { s = new Socket(ipAdress, post); br = new BufferedReader(new InputStreamReader(s.getInputStream())); os = s.getOutputStream(); MainActivity.socketStatue = 1; // 启动一条子线程来读取服务器相应的数据 new Thread() { public void run() { String content = null; // 不断读取Socket输入流中的内容 try { while ((content = br.readLine()) != null) { // 每当读取到来自服务器的数据后,发送消息通知程序界面显示该数据 Message msg = new Message(); msg.what = 0x123; msg.obj = content; handler.sendMessage(msg); } } catch (SocketException e) { System.out.println("Socket Reset!"); try { s.close(); System.out.println("Socket closed!"); } catch (IOException e1) { e1.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } }.start(); // 为当前线程初始化Looper Looper.prepare(); // 创建revHandler对象 recvHandler = new Handler() { public void handleMessage(Message msg) { // 接收到UI线程中用户输入的数据 if (msg.what == 0x345) { // 将用户在文本框内输入的内容写入网络 try { os.write((msg.obj.toString() + " ") .getBytes("utf-8")); } catch (Exception e) { e.printStackTrace(); } } } }; // 启动Looper Looper.loop(); } catch (SocketTimeoutException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }