Search code examples
androidandroid-permissionsandroid-wifi

Connect android device to wifi programmatically without user interaction


I need to connect an android device to wifi programmatically without interacting with the user. Notably, this app is being purpose built and will not be on the play store or deployed publicly (I say this because what I need to do could have serious security concerns).

Here is how I am connecting the device programmatically

TextView textFeedback = findViewById(R.id.text);


ConnectivityManager.NetworkCallback wifiConnectionCallback = new ConnectivityManager.NetworkCallback(){
    @Override
    public void onAvailable(@NonNull Network network) {
        super.onAvailable(network);
        Log.e(logTAG, "wifi connected");
        textFeedback.setText("wifi connected");
    }

    @Override
    public void onLosing(@NonNull Network network, int maxMsToLive) {
        super.onLosing(network, maxMsToLive);
        Log.e(logTAG, "losing wifi connection");
        textFeedback.setText("losing wifi connection");
    }

    @Override
    public void onLost(@NonNull Network network) {
        super.onLost(network);
        Log.e(logTAG, "lost wifi connection");
        textFeedback.setText("lost wifi connection");
    }

    @Override
    public void onUnavailable() {
        super.onUnavailable();
        Log.e(logTAG, "user closed wifi connection");
        textFeedback.setText("user closed wifi connection");
    }
};


// instantiate connectivity manager
ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(this.CONNECTIVITY_SERVICE);

// connect to phl via wifi
Thread wifiConnectionThread = new Thread(new Runnable()
{
    @Override
    public void run()
    {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
        {
            NetworkSpecifier networkSpecifier  = new WifiNetworkSpecifier.Builder()
                        .setSsid(ssid)
                        .build();
            NetworkRequest networkRequest  = new NetworkRequest.Builder()
                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        .setNetworkSpecifier(networkSpecifier)
                        .build();
            connectivityManager.requestNetwork(networkRequest, wifiConnectionCallback);
        }
    }
});
wifiConnectionThread.start();

This works just fine with one exception. It prompts the user to ask them if they would like to connect to the network. This is problematic because I need the device to connect even if there isn't a user (hence the need to do this programmatically, there often will not be a user around). Is there a way to do this (preferably without rooting the device)? For example, is it possible to set this up so that a user is only prompted once and from that point on it is automatic?


Solution

  • Some years ago I encountered that exact same problem while developing a small gateway to collect data from our BLE sensors and push it to our backend over Wi-Fi.

    At that time I used a small library publicly available in GitHub which is called WifiUtils. You can find that library following this link.

    It was pretty simple to use and you can get a lot of information from the README.md at GitHub.

    Enabling Wi-Fi:

    WifiUtils.withContext(getApplicationContext()).enableWifi();
    

    Scanning for Wi-Fi networks:

    WifiUtils.withContext(getApplicationContext()).scanWifi(this::getScanResults).start();
    
    private void getScanResults(@NonNull final List<ScanResult> results)
    {
        if (results.isEmpty())
        {
            Log.i(TAG, "SCAN RESULTS IT'S EMPTY");
            return;
        }
        Log.i(TAG, "GOT SCAN RESULTS " + results);
    }
    

    And finally connecting to them:

    WifiUtils.withContext(getApplicationContext())
        .connectWith("JohnDoeWiFi", "JohnDoePassword")
        .setTimeout(40000)
        .onConnectionResult(new ConnectionSuccessListener() {
            @Override
            public void success() {
                Toast.makeText(MainActivity.this, "SUCCESS!", Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void failed(@NonNull ConnectionErrorCode errorCode) {
                Toast.makeText(MainActivity.this, "EPIC FAIL!" + errorCode.toString(), Toast.LENGTH_SHORT).show();
            }
        })
        .start();
    

    As the library has all its code in GitHub, you might find much more information there.