Android项目中的问题,即使应用程序关闭,也可以获取用户位置并将其发送到后端服务器

问题描述 投票:0回答:1

我在我的应用程序中添加后台位置服务功能时遇到问题。该代码不起作用。我希望在后台每 1 分钟将用户的位置发送到后端服务器。但我没有在后端服务器上受到攻击,我认为我的代码存在与用户位置相关的问题。即使我也没有进入该位置的 Android 代码。也许我的代码中有一些。

下面是我的MainActivity代码

package ses.hasnain.sesproduct;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static ses.hasnain.sesproduct.BuildConfig.VERSION_NAME;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;

import java.util.ArrayList;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ses.hasnain.sesproduct.Database.DBHelper;
import ses.hasnain.sesproduct.Retrofit.ApiClient;
import ses.hasnain.sesproduct.Retrofit.RequestApi;
import ses.hasnain.sesproduct.Retrofit.SpinnerData;
import ses.hasnain.sesproduct.Retrofit.Tasks;
import ses.hasnain.sesproduct.SharedPreference.SaveSharedPreference;
import ses.hasnain.sesproduct.UXFragments.ActiveProjects;
import ses.hasnain.sesproduct.UXFragments.CEODashboard;
import ses.hasnain.sesproduct.UXFragments.ChangePassword;
import ses.hasnain.sesproduct.UXFragments.Dashboard;
import ses.hasnain.sesproduct.UXFragments.LocationCheck;
import ses.hasnain.sesproduct.UXFragments.Login;
import ses.hasnain.sesproduct.UXFragments.MarkAttendance;
import ses.hasnain.sesproduct.UXFragments.MyJobIntentService;
import ses.hasnain.sesproduct.UXFragments.NotificationList;
import ses.hasnain.sesproduct.UXFragments.Splash;
import ses.hasnain.sesproduct.UXFragments.SyncData;

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    @SuppressLint("StaticFieldLeak")
    public static Toolbar toolbar;
    @SuppressLint("StaticFieldLeak")
    public static TextView nav_username;
    @SuppressLint("StaticFieldLeak")
    public static ImageView profile_pic;
    @SuppressLint("StaticFieldLeak")
    public static FrameLayout redCircle;
    @SuppressLint("StaticFieldLeak")
    public static TextView countTextView;
    @SuppressLint("StaticFieldLeak")
    public static Context activity;
    public static FloatingActionButton fab;
    public static DrawerLayout drawer;
    public static NavigationView navigationView;
    public static String UserId = null;
    public static String UserIndex = null;
    public static String UserImage = null;
    public static String CompanyID = null;
    public static String versionName = null;
    public static boolean logoutStatus = false;
    public static DBHelper db;
    public static int alertCount = 0;
    private static ProgressDialog progress;
    Context context;

    private boolean isFirstLaunch = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        versionName = VERSION_NAME;
        activity = this;
        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        context = getBaseContext();
        db = new DBHelper(getApplicationContext());
        fab = findViewById(R.id.fab);
        fab.setOnClickListener(view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show());
        drawer =  findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        navigationView =  findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
        getSupportFragmentManager().beginTransaction().add(R.id.frameLayout, new Splash()).commit();
        Handler handler = new Handler();
        Intent mIntent = new Intent(context, MyJobIntentService.class);
        mIntent.putExtra("maxCountValue", 1500);
        final Runnable r = new Runnable() {
            public void run() {
                MyJobIntentService.enqueueWork(context,mIntent);
                handler.postDelayed(this, 1000);
            }
        };

        handler.postDelayed(r, 1000);


    }
    @Override
    public void onBackPressed() {
        DrawerLayout drawer =  findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else if (logoutStatus) {
            System.exit(0);
        } else {
            super.onBackPressed();
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        alertCount = 0;
        final MenuItem alertMenuItem = menu.findItem(R.id.activity_main_alerts_menu_item);
        FrameLayout rootView = (FrameLayout) alertMenuItem.getActionView();
        redCircle = rootView.findViewById(R.id.view_alert_red_circle);
        countTextView = rootView.findViewById(R.id.view_alert_count_textview);
        redCircle.setVisibility((alertCount > 0) ? VISIBLE : GONE);
        rootView.setOnClickListener(v -> onOptionsItemSelected(alertMenuItem));
        return true;
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        switch (item.getItemId()) {
            case R.id.action_refresh:
                updateAlertIcon();
                return true;

            case R.id.activity_main_alerts_menu_item:
                alertCount = 0;
                redCircle.setVisibility(GONE);
                getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new NotificationList()).commit();
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void updateAlertIcon() {
        alertCount = 0;
        RequestApi api = ApiClient.getInstance();
        Call<ArrayList<Tasks>> call = api.getCountTotal("getCountTotal", MainActivity.UserIndex, MainActivity.CompanyID);
        call.enqueue(new Callback<ArrayList<Tasks>>() {
            @Override
            public void onResponse(@NonNull Call<ArrayList<Tasks>> call, @NonNull Response<ArrayList<Tasks>> response) {
                if (response.isSuccessful()) {
                    assert response.body() != null;
                    Tasks data = response.body().get(0);
                    alertCount = Integer.parseInt(data.getTaskpopup()) + Integer.parseInt(data.getFollowuppopup());
                    //      if alert count extends into two digits, just show the red circle
                    if (0 < alertCount) {
                        if (alertCount > 10) {
                            String text = alertCount + "+";
                            countTextView.setText(text);
                        } else
                            countTextView.setText(String.valueOf(alertCount));
                    } else {
                        countTextView.setText("");
                    }
                    redCircle.setVisibility((alertCount > 0) ? VISIBLE : GONE);
                }

            }

            @Override
            public void onFailure(@NonNull Call<ArrayList<Tasks>> call, @NonNull Throwable t) {
                Toast.makeText(getBaseContext(), "Failed to connect with server", Toast.LENGTH_LONG).show();
            }
        });
    }


    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();
        if (id == R.id.dashboard) {
            getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, new Dashboard()).commit();
        } else if (id == R.id.logout) {
            LogoutSession(getBaseContext(), SaveSharedPreference.getuserIndex(getBaseContext()), SaveSharedPreference.getcompany_ID(getBaseContext()));
        } else if (id == R.id.ceo_dashboard) {
            getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, new CEODashboard()).commit();
        } else if (id == R.id.nav_password) {
            getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, new ChangePassword()).commit();
        } else if (id == R.id.nav_syncData) {
            getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new SyncData()).commit();
        } else if (id == R.id.activeProjects) {
            getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new ActiveProjects()).commit();
        } else if(id==R.id.mark_attendance){
            getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new MarkAttendance()).commit();
        }
        DrawerLayout drawer =  findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    public static void startProgress(boolean isCancelable) {
        stopProgress();
        progress = new ProgressDialog(activity, R.style.ProgressBarTheme);
        progress.setProgressStyle(android.R.style.Widget_ProgressBar_Small);
        progress.setIndeterminate(true);
        progress.setCancelable(isCancelable);
        progress.setCanceledOnTouchOutside(isCancelable);
        progress.show();
    }


    public static void stopProgress() {
        if (null != progress && progress.isShowing()) {
            progress.dismiss();
        }
    }

    private void LogoutSession(final Context context, final String userIndex, final String CompanyName) {
        RequestApi api = ApiClient.getInstance();
        Call<ArrayList<SpinnerData>> call = api.LogoutSession("LogoutSession", userIndex, CompanyName);
        call.enqueue(new Callback<ArrayList<SpinnerData>>() {
            @Override
            public void onResponse(@NonNull Call<ArrayList<SpinnerData>> call, @NonNull Response<ArrayList<SpinnerData>> response) {
                if (response.isSuccessful()) {
                    SaveSharedPreference.removeValues(context);
                    db.deleteDatabase();
                    MainActivity.logoutStatus = true;
                    Bundle bundle = new Bundle();
                    bundle.putString("pCheck", "0");
                    bundle.putString("link", "");
                    Login login = new Login();
                    login.setArguments(bundle);
                    Toast.makeText(context, "You have successfully logged out from the application.", Toast.LENGTH_LONG).show();
                    getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, login).commit();
                }
            }

            @Override
            public void onFailure(@NonNull Call<ArrayList<SpinnerData>> call, @NonNull Throwable t) {
                Toast.makeText(context, "Unable to connect the server at this time, please try again later.", Toast.LENGTH_LONG).show();

            }
        });
    }

    @Override
    protected void onDestroy() {
        db = new DBHelper(getBaseContext());
        super.onDestroy();
        Intent mIntent = new Intent(context, MyJobIntentService.class);
        mIntent.putExtra("maxCountValue", 1500);
        MyJobIntentService.enqueueWork(context, mIntent);
    }
}

下面是我的 MyJobIntent 代码,我正在其中完成用户位置的所有工作

package ses.hasnain.sesproduct.UXFragments;

import static ses.hasnain.sesproduct.UXFragments.ScheduledService.context;

import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.app.NotificationCompat;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ses.hasnain.sesproduct.Database.DBHelper;
import ses.hasnain.sesproduct.R;
import ses.hasnain.sesproduct.Retrofit.ApiClient;
import ses.hasnain.sesproduct.Retrofit.FormSubmitPOJO;
import ses.hasnain.sesproduct.Retrofit.RequestApi;
import ses.hasnain.sesproduct.SharedPreference.SaveSharedPreference;

public class MyJobIntentService extends JobIntentService implements LocationListener {
    private static final String TAG = "MyJobIntentService";
    private static final int JOB_ID = 39992;

    private static DBHelper db;
    private static Context activity;
    private static LocationManager locationManager;
    private static boolean isTrackingStarted = false;
    private static boolean isSendingData = false;
    private static int idCheck = 0;

    private static final int INITIAL_DELAY = 0; // Start immediately
    private static final int INTERVAL = 60 * 1000; // Every 1 minute

    private static final String CHANNEL_ID = "LocationTrackingChannel";
    private static final String CHANNEL_NAME = "Location Tracking";

    @Override
    public void onCreate() {
        super.onCreate();
        db = new DBHelper(getApplicationContext());
        activity = getApplicationContext();
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        if (!isTrackingStarted) {
            startForegroundService();
            isTrackingStarted = true;
        }

        scheduleLocationUpdates();
    }

    // Start a foreground service for continuous location tracking
    private void startForegroundService() {
        createNotificationChannel();

        Intent notificationIntent = new Intent(this, MyJobIntentService.class);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Location Tracking")
                .setContentText("Tracking your location in background")
                .build();

        startForeground(1, notification);

        // Start tracking location
        startLocationTracking();
    }

    // Schedule periodic tasks to send location data to backend
    private void scheduleLocationUpdates() {
        if (!isSendingData) {
            isSendingData = true;
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    sendLocationDataToBackend();
                    handler.postDelayed(this, INTERVAL);
                }
            }, INITIAL_DELAY);
        }
    }

    // Method to send location data to backend
    private void sendLocationDataToBackend() {
        Location location = getLastKnownLocation();
        if (location != null) {
            String lat = String.valueOf(location.getLatitude());
            String lon = String.valueOf(location.getLongitude());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
            String currentDateandTime = sdf.format(new Date());

            // Assuming ActionID is fixed for your case, adjust as needed
            String actionId = "insertEmployeeLoc";

            // Insert data to backend via Retrofit
            RequestApi api = ApiClient.getInstance();
            Call<ArrayList<FormSubmitPOJO>> call = api.InsertEmployeeLoc(actionId, lat, lon, currentDateandTime,
                    String.valueOf(idCheck), SaveSharedPreference.getuserIndex(activity),
                    SaveSharedPreference.getcompany_ID(activity));

            call.enqueue(new Callback<ArrayList<FormSubmitPOJO>>() {
                @Override
                public void onResponse(Call<ArrayList<FormSubmitPOJO>> call, Response<ArrayList<FormSubmitPOJO>> response) {
                    if (response.isSuccessful()) {
                        Toast.makeText(context, "Permission granted", Toast.LENGTH_LONG).show();
                    } else {
                        Toast.makeText(context, "Permission denied", Toast.LENGTH_LONG).show();
                    }
                }

                @Override
                public void onFailure(Call<ArrayList<FormSubmitPOJO>> call, Throwable t) {
                    Toast.makeText(context, "Server Error", Toast.LENGTH_LONG).show();
                }
            });
        }
    }

    // Helper method to get last known location
    private Location getLastKnownLocation() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return null;
            }
        }
        return locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    }

    // Start tracking location if it's not already started
    private void startLocationTracking() {
        // Implement your logic to start tracking location here
        // This typically involves setting up a location listener
        // and requesting location updates from LocationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
    }

    // Create notification channel for foreground service
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    CHANNEL_NAME,
                    NotificationManager.IMPORTANCE_DEFAULT
            );

            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(serviceChannel);
            }
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        // Handle location updates here if needed
    }

    // Other LocationListener methods
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}

    @Override
    public void onProviderEnabled(String provider) {}

    @Override
    public void onProviderDisabled(String provider) {}

    // Enqueue work method to start the service
    public static void enqueueWork(Context context, Intent intent) {
        activity = context;
        enqueueWork(context, MyJobIntentService.class, JOB_ID, intent);
    }
}
java android mobile google-maps-api-3 location
1个回答
0
投票

好的,请告诉我您的服务等级是否被触发?你检查了吗?

如果否,请在清单中注册您的服务。

<application>
....
<service android:enabled="true" android:name=".MyJobIntentService " />
</application>
© www.soinside.com 2019 - 2024. All rights reserved.