2010-03-25 61 views
29

如何在Android應用程序中使用3G連接而不是Wi-Fi?如何在Android應用程序中使用3G連接而不是Wi-Fi?

我想連接3G連接,是否有任何示例代碼連接到3G而不是Wi-fi?

+1

爲什麼不打開無線連接首選項,讓用戶自己禁用wifi。相當侵擾性,但用戶在掌控之中。 – MrSnowflake 2010-03-25 15:00:25

+0

我正在尋找一種方法來做到這一點,但我正在尋找「優先」(我認爲這將是正確的名稱),而不是「偏好」。感謝您的好問題和答案。 – 2011-12-03 13:37:06

+0

@MsSnowflake如果您想要通過網絡接口分配負載,或者您信任一個接口上的敏感信息,並且希望通過可信通道和其他流量通過不可信通道路由敏感流量,或者您擔心其中一個接口更多很可能會在大量下載過程中退出,或者您只是希望爲用戶提供清晰細緻的應用程序特定權限,但您不希望打開* global *設置頁面來解決特定於應用程序的問題。 – 2014-06-11 17:10:54

回答

13

T-Mobile的「我的帳戶」應用程序會這樣做,如果您連接到WiFi連接,它會告訴您他們的程序無法通過WiFi工作,然後詢問用戶是否要關閉WiFi連接。如果你選擇「否」,那麼應用程序退出,如果你選擇「是」,那麼應用程序關閉你的WiFi連接,然後繼續啓動。

我認爲這是一個很好的模型,它會確保您的應用程序不會在WiFi上運行,並允許用戶決定是否要關閉WiFi。對此模型的改進是在用戶從您的應用程序導航離開時將WiFi重新開啓。沒有測試過d下面的代碼,但它看起來像它應該工作(從here修改)

使用下面的權限,您的清單

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

,這裏是一些實際的代碼來打開WiFi /關閉

private WifiManager wifiManager; 

@Override 
public void onCreate(Bundle icicle) 
{ 
    .................... 

    wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE); 

    if(wifiManager.isWifiEnabled()) 
    { 
     wifiManager.setWifiEnabled(false); 
    } 
    else 
    { 
     wifiManager.setWifiEnabled(true); 
    } 
} 

如果你不想沿着這條路線走,看起來你可能會告訴手機你更喜歡使用移動數據網絡而不是WiFi網絡。

Android ConnectivityManager提供功能setNetworkPreference。這個功能沒有真正的記錄,因爲你可以告訴你是否點擊鏈接。我會仔細研究它,因爲定義的常量似乎暗示您可以將其設置爲TYPE_MOBILETYPE_WIFI,並且還有一個DEFAULT_NETWORK_PREFERENCE常量,它被定義爲0x00000001,它與TYPE_WIFI相同。因此,請嘗試通過調用

Context.getSystemService(Context.CONNECTIVITY_SERVICE); 

訪問ConnectivityManager,然後嘗試使用setNetworkPreference()函數。

它似乎不需要清單中的任何權限,但它可能需要CHANGE_NETWORK_STATE權限或沿着這些行的東西。

如果你起訴setNetworkPreference功能它很可能是最好也設置網絡偏好回原來的值(從getNetworkPreference收到)

我希望這有助於。

+2

雖然有用,但從@Rainbowbreeze得到的答案是正確的答案。 – Josh 2014-02-01 05:38:53

4

我認爲這是不可能從Java。如果連接到無線網絡,系統將關閉所有基於移動網絡的通信。我認爲你不能從你的程序開始3G連接。

+0

感謝q如果移動用戶啓用都意味着3G和WiFi,那時候我的應用程序運行失敗,因爲它不斷跳到WiFi和3G到WiFi可以u pl給任何替代解決方案 – Aswan 2010-03-25 14:04:01

+2

有沒有辦法解決這個問題。如果用戶有一個非常明顯的3G連接,她會一直得到網絡和鬆散的網絡連接。 您可以做的唯一的事情就是對您的服務器做小而頻繁的請求,並且不要試圖保持連接長時間打開。 然後以適當的方式處理網絡錯誤,可能會重試它或建議用戶稍後嘗試使用更穩定的連接。 – Janusz 2010-03-25 15:38:20

+0

我很抱歉,但Android上的東西真的很糟糕。我測試了2個BSD插座綁定到Wi-Fi,另一個到3G IP地址。當Android切換到另一種網絡類型時,Android確實會阻塞一個套接字(不接收數據包)。如果使用connectedManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI,hostAddress);''''與connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,「enableHIPRI」);'''你有一個套接字,你綁定到另一個地址接收不對應的數據包 - 更糟糕。 – 2015-04-23 23:32:16

60
/** 
* Enable mobile connection for a specific address 
* @param context a Context (application or activity) 
* @param address the address to enable 
* @return true for success, else false 
*/ 
private boolean forceMobileConnectionForAddress(Context context, String address) { 
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
    if (null == connectivityManager) { 
     Log.debug(TAG_LOG, "ConnectivityManager is null, cannot try to force a mobile connection"); 
     return false; 
    } 

    //check if mobile connection is available and connected 
    State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); 
    Log.debug(TAG_LOG, "TYPE_MOBILE_HIPRI network state: " + state); 
    if (0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING)) { 
     return true; 
    } 

    //activate mobile connection in addition to other connection already activated 
    int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI"); 
    Log.debug(TAG_LOG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt); 

    //-1 means errors 
    // 0 means already enabled 
    // 1 means enabled 
    // other values can be returned, because this method is vendor specific 
    if (-1 == resultInt) { 
     Log.error(TAG_LOG, "Wrong result of startUsingNetworkFeature, maybe problems"); 
     return false; 
    } 
    if (0 == resultInt) { 
     Log.debug(TAG_LOG, "No need to perform additional network settings"); 
     return true; 
    } 

    //find the host name to route 
    String hostName = StringUtil.extractAddressFromUrl(address); 
    Log.debug(TAG_LOG, "Source address: " + address); 
    Log.debug(TAG_LOG, "Destination host address to route: " + hostName); 
    if (TextUtils.isEmpty(hostName)) hostName = address; 

    //create a route for the specified address 
    int hostAddress = lookupHost(hostName); 
    if (-1 == hostAddress) { 
     Log.error(TAG_LOG, "Wrong host address transformation, result was -1"); 
     return false; 
    } 
    //wait some time needed to connection manager for waking up 
    try { 
     for (int counter=0; counter<30; counter++) { 
      State checkState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); 
      if (0 == checkState.compareTo(State.CONNECTED)) 
       break; 
      Thread.sleep(1000); 
     } 
    } catch (InterruptedException e) { 
     //nothing to do 
    } 
    boolean resultBool = connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress); 
    Log.debug(TAG_LOG, "requestRouteToHost result: " + resultBool); 
    if (!resultBool) 
     Log.error(TAG_LOG, "Wrong requestRouteToHost result: expected true, but was false"); 

    return resultBool; 
} 

這對於計算主機地址:

/** 
* This method extracts from address the hostname 
* @param url eg. http://some.where.com:8080/sync 
* @return some.where.com 
*/ 
public static String extractAddressFromUrl(String url) { 
    String urlToProcess = null; 

    //find protocol 
    int protocolEndIndex = url.indexOf("://"); 
    if(protocolEndIndex>0) { 
     urlToProcess = url.substring(protocolEndIndex + 3); 
    } else { 
     urlToProcess = url; 
    } 

    // If we have port number in the address we strip everything 
    // after the port number 
    int pos = urlToProcess.indexOf(':'); 
    if (pos >= 0) { 
     urlToProcess = urlToProcess.substring(0, pos); 
    } 

    // If we have resource location in the address then we strip 
    // everything after the '/' 
    pos = urlToProcess.indexOf('/'); 
    if (pos >= 0) { 
     urlToProcess = urlToProcess.substring(0, pos); 
    } 

    // If we have ? in the address then we strip 
    // everything after the '?' 
    pos = urlToProcess.indexOf('?'); 
    if (pos >= 0) { 
     urlToProcess = urlToProcess.substring(0, pos); 
    } 
    return urlToProcess; 
} 

/** 
* Transform host name in int value used by {@link ConnectivityManager.requestRouteToHost} 
* method 
* 
* @param hostname 
* @return -1 if the host doesn't exists, elsewhere its translation 
* to an integer 
*/ 
private static int lookupHost(String hostname) { 
    InetAddress inetAddress; 
    try { 
     inetAddress = InetAddress.getByName(hostname); 
    } catch (UnknownHostException e) { 
     return -1; 
    } 
    byte[] addrBytes; 
    int addr; 
    addrBytes = inetAddress.getAddress(); 
    addr = ((addrBytes[3] & 0xff) << 24) 
      | ((addrBytes[2] & 0xff) << 16) 
      | ((addrBytes[1] & 0xff) << 8) 
      | (addrBytes[0] & 0xff); 
    return addr; 
} 

而且下列權限必須添加到AndroidManifest。XML

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

它僅適用於Android 2.2以上版本,兩個歌Nexus One和LG擎天柱測試,其他手機我不知道,因爲ConnectivityMananger的一些方法是供應商特定的。 閒置15-20秒後,移動網絡會自動斷開連接。

+2

我不能滿足這個。這正是我所需要的,並且像魅力一樣工作而不需要改變任何東西。這是我在整個互聯網上爲這個問題找到的唯一很好的解決方案。 – Robber 2013-04-06 14:25:32

+2

我的工作就像一個魅力一樣快。我必須定期(每隔30秒左右)調用startUsingNetworkFeature,否則即使在傳輸數據時也會斷開連接。有了這個解決方法,我還沒有遇到任何其他問題。謝謝! – Robber 2013-04-06 17:50:46

+0

除了這個優秀的答案,如果有人想打開一個關機的數據連接,我會建議從這個答案添加一個調用方法: http://stackoverflow.com/a/11555457/2347363 可以在這行之前調用: 「for(int counter = 0; counter <30; counter ++)」 這樣,如果數據切換關閉,它也可以工作 – Antilope 2015-01-09 20:57:15

2

使用連接管理器並根據需要設置網絡首選項。 好luk

例如: dataManager =(ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE); dataManager.setNetworkPreference(ConnectivityManager.TYPE_MOBILE); dataManager.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);

+1

ConnectivityManager.setNetworkPreference()已接近廢棄。但更重要的是,如果在更改之前獲取NetWorkPreference(),它將返回ConnectivityManager.TYPE_MOBILE。在那裏設置沒有任何區別。至於HIPRI本身,它的工作方式非常奇怪。首先,它允許連接到所有主機,而不僅僅是通過路由明確請求的主機。其次,當您使用stopUsingFeature ...()調用將其關閉時,它不會被關閉,並且仍然處於活動狀態。第三,即使無線網絡可用,所有的應用程序都會使用它,這與文檔相矛盾。 – 2013-12-22 09:44:34

1

受此門票中的代碼的啓發,並使用它的一些部分,這裏是建立hipri移動並使其保持運行的服務。

import java.net.InetAddress; 
import java.net.UnknownHostException; 
import java.util.concurrent.atomic.AtomicBoolean; 

import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.net.ConnectivityManager; 
import android.net.NetworkInfo.State; 
import android.os.IBinder; 
import android.util.Log; 

public class HipriService extends Service { 
    private AtomicBoolean enabledMobile = new AtomicBoolean(false); 

    public boolean enableMobileConnection() { 
     ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
     if (null == cm) { 
      Log.d(TAG, "ConnectivityManager is null, cannot try to force a mobile connection"); 
      return false; 
     } 

     /* 
     * Don't do anything if we are connecting. On the other hands re-new 
     * connection if we are connected. 
     */ 
     State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); 
     Log.d(TAG, "TYPE_MOBILE_HIPRI network state: " + state); 
     if (0 == state.compareTo(State.CONNECTING)) 
      return true; 

     /* 
     * Re-activate mobile connection in addition to other connection already 
     * activated 
     */ 
     int resultInt = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI"); 
     //Log.d(TAG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt); 

     //-1 means errors 
     // 0 means already enabled 
     // 1 means enabled 
     // other values can be returned, because this method is vendor specific 
     if (-1 == resultInt) { 
      Log.e(TAG, "Wrong result of startUsingNetworkFeature, maybe problems"); 
      return false; 
     } 
     if (0 == resultInt) { 
      Log.d(TAG, "No need to perform additional network settings"); 
      return true; 
     } 

     return requestRouteToHost(this, Uploader.ServerAddress); 
    } 

    private Thread pingerThread = null; 

    private void startMobileConnection() { 
     enabledMobile.set(true); 
     pingerThread = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       while (enabledMobile.get()) { 
        /* 
        * Renew mobile connection. No routing setup is needed. This 
        * should be moved to 3g monitoring service one day. 
        */ 
        enableMobileConnection(); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         // do nothing 
        } 
       } 
      } 
     }); 
     pingerThread.start(); 
    } 

    private void stopMobileConnection() { 
     enabledMobile.set(false); 
     disableMobileConnection(); 
     pingerThread.interrupt(); 
     pingerThread = null; 
    } 

    public void disableMobileConnection() { 
     ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
     cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI"); 
    } 

    public final static int inetAddressToInt(InetAddress inetAddress) { 
     byte[] addrBytes; 
     int addr; 
     addrBytes = inetAddress.getAddress(); 
     addr = ((addrBytes[3] & 0xff) << 24) | ((addrBytes[2] & 0xff) << 16) | ((addrBytes[1] & 0xff) << 8) 
       | (addrBytes[0] & 0xff); 
     return addr; 
    } 

    public final static InetAddress lookupHost(String hostname) { 
     try { 
      return InetAddress.getByName(hostname); 
     } catch (UnknownHostException e) { 
      return null; 
     } 
    } 

    private boolean requestRouteToHost(Context context, String hostname) { 
     ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
     if (null == cm) { 
      Log.d(TAG, "ConnectivityManager is null, cannot try to force a mobile connection"); 
      return false; 
     } 

     /* Wait some time needed to connection manager for waking up */ 
     try { 
      for (int counter = 0; enabledMobile.get() && counter < 30; counter++) { 
       State checkState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); 
       Log.i(TAG, "Waiting for mobile data on. State " + checkState); 
       if (0 == checkState.compareTo(State.CONNECTED)) 
        break; 
       Thread.sleep(1000); 
      } 
     } catch (InterruptedException e) { 
      //nothing to do 
     } 

     if (!enabledMobile.get()) { 
      Log.d(TAG, "Mobile data is turned off while waiting for routing."); 
      return false; 
     } 

     State checkState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); 
     if (0 != checkState.compareTo(State.CONNECTED)) { 
      Log.e(TAG, "Mobile data is still turned off after 30 sec of waiting."); 
      return false; 
     } 
     Log.i(TAG, "Adding routing for " + hostname); 

     InetAddress inetAddress = lookupHost(hostname); 
     if (inetAddress == null) { 
      Log.e(TAG, "Failed to resolve " + hostname); 
      return false; 
     } 
     int hostAddress = inetAddressToInt(inetAddress); 

     boolean resultBool = cm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress); 
     Log.d(TAG, "requestRouteToHost result: " + resultBool); 
     if (!resultBool) 
      Log.e(TAG, "Wrong requestRouteToHost result: expected true, but was false"); 

     return resultBool; 
    } 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     startMobileConnection(); 
    } 

    @Override 
    public void onDestroy() { 
     stopMobileConnection(); 
     super.onDestroy(); 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 

} 

這是我如何在需要時啓動/停止它。請注意,它也會鎖定cpu和wifi,以便在手機睡眠時運行(僅限屏幕)。 Wifi是需要的,因爲我的應用程序是WiFi和移動連接之間的橋樑。你可能不需要它。

public void startMobileData() { 
    if (!enabledMobile.get()) { 
     enabledMobile.set(true); 
     WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE); 
     wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, "Wifi Wakelock"); 
     wifiLock.acquire(); 

     PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 
     partialLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "3G Wakelock"); 
     partialLock.acquire(); 

     startService(new Intent(this, HipriService.class)); 
    } 
} 

public void stopMobileData() { 
    if (enabledMobile.get()) { 
     enabledMobile.set(false); 
     Log.i(TAG, "Disabled mobile data"); 
     stopService(new Intent(this, HipriService.class)); 

     if (partialLock != null) { 
      partialLock.release(); 
      partialLock = null; 
     } 

     if (wifiLock != null) { 
      wifiLock.release(); 
      wifiLock = null; 
     } 
    } 
} 

不要忘記爲您的清單文件添加服務。

0

@umka

  • 我認爲,應用只能達到通過HIPRI它已經請求的那些宿主,可以是用於其他主機(其路由請求)使用默認網絡(MOBILE或WIFI )。
  • 打電話stopUsingNetworkFeature(),它會檢查 - 是否有任何其他應用程序正在使用此網絡,如果是,那麼它將忽略您的請求關閉此網絡功能。
  • HIPRI網絡的主要目的之一就是 - 如果wifi在運行並且一個應用想要使用移動網絡(3G)到達特定的主機,它可以通過HIPRI網絡到達。
3

以下是適用於API 21+(棒棒糖,棉花糖..)的代碼。 我更喜歡使用OkHttp與Network.getSocketFactory(),但Network.openURLConnection()也正常工作。

private void doTest() 
{ 
    display("Requesting CELLULAR network connectivity..."); 
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 

    NetworkRequest request = new NetworkRequest.Builder() 
      .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 
      .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build(); 

    connectivityManager.requestNetwork(request, new ConnectivityManager.NetworkCallback() 
    { 
     /** 
     * Called when the framework connects and has declared a new network ready for use. 
     * This callback may be called more than once if the {@link Network} that is 
     * satisfying the request changes. 
     * 
     * This method will be called on non-UI thread, so beware not to use any UI updates directly. 
     * 
     * @param network The {@link Network} of the satisfying network. 
     */ 
     @Override 
     public void onAvailable(final Network network) 
     { 
      display("Got available network: " + network.toString()); 

      try 
      { 
       final InetAddress address = network.getByName("navalclash.com"); 
       display("Resolved host2ip: " + address.getHostName() + " -> " + address.getHostAddress()); 
      } 
      catch (UnknownHostException e) 
      { 
       e.printStackTrace(); 
      } 

      display("Do request test page from remote http server..."); 

      if(okHttpClient == null) 
      { 
       okHttpClient = new OkHttpClient.Builder().socketFactory(network.getSocketFactory()).build(); 
      } 

      Request request = new Request.Builder() 
        .url("http://navalclash.com") 
        .build(); 
      try (Response response = okHttpClient.newCall(request).execute()) 
      { 
       display("RESULT:\n" + response.body().string()); 
      } 
      catch (Exception ex) 
      { 
       ex.printStackTrace(); 
      } 
     } 
    }); 
} 
+0

OkHttp似乎沒有爲我工作(這很奇怪),但network.openURLConnection()做到了。 – user1691694 2017-01-03 05:23:27

相關問題