Is is possible to create JobService Job Scheduler in Extensions

Hi, please i need to know is it possible to create JobService Job Scheduler in Extension, it's require minSdk Version 21, how to set minSdk Version 21 in Extension creation.

In the @DesignerComponent annotation, you can set the androidMinSdk field to 21. This will make compiled apps require a minimum SDK or 21. However, you'll still want to put checks in the code in the event that someone uses the extension in the companion on Android versions prior to SDK 21.

2 Likes

Thanks sir,

Hi, I have created extension with three methods ScheduleJob, CancelJob and CheckJobIsRunning but when i using in my kodular app it gives Runtime Error "No such service ComponentInfo(com.hgosai.TestJobServiceApp/com.hgosai.TestJobServiceApp.JobServiceTest)" when i click on Start Service button below screen shot

then it show me error in below screen shot it execute
method ScheduleJob

Below three methods in TestJobServiceApp.java file :

  1. ScheduleJob Method Code;

@UsesServices(services = {@ServiceElement(name = "com.hgosai.TestJobServiceApp.JobServiceTest", permission = "android.permission.BIND_JOB_SERVICE", enabled = "true", exported = "true")})
@SimpleFunction(description = "Start Schedule Job ")
public void ScheduleJob(){
ComponentName componentName = new ComponentName("com.hgosai.TestJobServiceApp",JobServiceTest.class.getName());
JobInfo info = new JobInfo.Builder(456,componentName)
.setPeriodic(15601000)
.setPersisted(true)
.build();
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
try {
ClipboardManager clipboardPaste = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
Date currentDate = new Date();
clipTime = dateFormat.format(currentDate);
ClipData clip = ClipData.newPlainText("Copy", "Start Service : " + clipTime);
clipboardPaste.setPrimaryClip(clip);
} catch (NullPointerException ignored) {
}
int resultCode = scheduler.schedule(info);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
//Log.d("JobSechedu", "Job Scheduled");
Toast.makeText(context,"Job Shceduled : ",Toast.LENGTH_LONG).show();

    } else {
       //Log.d("JobFailed","Job Failed");
        Toast.makeText(context,"Job Failed : ",Toast.LENGTH_LONG).show();
    
    } 
    
           
    Toast.makeText(context, "Start Job Service : ", Toast.LENGTH_LONG).show();

}
  1. CancelJob Method code

@SimpleFunction(description = "Cancel Job ")
public void CancelJob(){
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.cancel(456);

    //Log.d("JobCancelled", "Job Cancelled");
    Toast.makeText(context,"Job Cancelled : ",Toast.LENGTH_LONG).show();
}
  1. CheckJobIsRunning method code:

@SimpleFunction(description = "Check Job is Running or Not ")
public void CheckJobIsRunning(){
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE ) ;
boolean hasBeenScheduled = false ;
for ( JobInfo jobInfo : scheduler.getAllPendingJobs() ) {
if ( jobInfo.getId() == 456 ) {
hasBeenScheduled = true ;
break ;
}
}

    if (hasBeenScheduled==true){
        Toast.makeText(context,"Job is Running : ",Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(context,"Job is Not Running : ",Toast.LENGTH_LONG).show();
    }
    //return hasBeenScheduled;
}

I created two java files 1. TestJobServiceApp.java 2. JobServiceTest.java

Below the code in TestJobServiceApp.java file

import com.hgosai.TestJobServiceApp.JobServiceTest;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.app.job.JobService;
import android.app.job.JobParameters;
@DesignerComponent(version = 1,
description = "Job Service for Run App in Background on every 15 Minutes ",
category = ComponentCategory.EXTENSION,
nonVisible = true,
androidMinSdk = 21,
iconName = "aiwebres/job_service.png" )
@SimpleObject(external = true)
@UsesPermissions(permissionNames =
"android.permission.WAKE_LOCK," +
"android.permission.SYSTEM_ALERT_WINDOW," +
"android.permission.RECEIVE_BOOT_COMPLETED," +
"android.permission.READ_EXTERNAL_STORAGE," +
"android.permission.BIND_JOB_SERVICE" )
//@UsesPermissions({WAKE_LOCK,SYSTEM_ALERT_WINDOW})

public class TestJobServiceApp extends AndroidNonvisibleComponent implements Component {

private ComponentContainer container;
private Context context; 	
public String clipTime;
public static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss a");
public String strStartJobSer = "StartJobService";
public String strStopJobSer = "StopJobService";

public TestJobServiceApp(ComponentContainer container) {
    super(container.$form());
    this.container = container;
//thisComponent = this;
    context = (Context) container.$context();
//Context context = container.$context();
    
} 

@UsesServices(services = {@ServiceElement(name = "com.hgosai.TestJobServiceApp.JobServiceTest", permission = "android.permission.BIND_JOB_SERVICE", enabled = "true", exported = "true")})
@SimpleFunction(description = "Start Schedule Job ")
public void ScheduleJob(){
ComponentName componentName = new ComponentName("com.hgosai.TestJobServiceApp",JobServiceTest.class.getName());
JobInfo info = new JobInfo.Builder(456,componentName)
.setPeriodic(15601000)
.setPersisted(true)
.build();
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

    int resultCode = scheduler.schedule(info);
    if (resultCode == JobScheduler.RESULT_SUCCESS) {
        //Log.d("JobSechedu", "Job Scheduled");
        Toast.makeText(context,"Job Shceduled : ",Toast.LENGTH_LONG).show();

              
    } else {
       //Log.d("JobFailed","Job Failed");
        Toast.makeText(context,"Job Failed : ",Toast.LENGTH_LONG).show();
        //finish();
    } 
    
           
    Toast.makeText(context, "Start Job Service : ", Toast.LENGTH_LONG).show();

}


@SimpleFunction(description = "Cancel Job ")
public void CancelJob(){
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    scheduler.cancel(456);

   

    //Log.d("JobCancelled", "Job Cancelled");
    Toast.makeText(context,"Job Cancelled : ",Toast.LENGTH_LONG).show();
}


@SimpleFunction(description = "Check Job is Running or Not ")
public void CheckJobIsRunning(){
    JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE ) ;
    boolean hasBeenScheduled = false ;
    for ( JobInfo jobInfo : scheduler.getAllPendingJobs() ) {
        if ( jobInfo.getId() == 456 ) {
            hasBeenScheduled = true ;
            break ;
        }
    }

    if (hasBeenScheduled==true){
        Toast.makeText(context,"Job is Running : ",Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(context,"Job is Not Running : ",Toast.LENGTH_LONG).show();
    }
    //return hasBeenScheduled;
}

}

Below the code in JobServiceTest.java file:

import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
public class JobServiceTest extends JobService {
//private Boolean jobcancelled=false;

Handler handler = new Handler();
Runnable runnable;
int delay1 = 5000, delay2 = 10000;
int i = 0;
public String clipTime;
public static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss a");

public String strStartJobSer = "StartJobService";
public String strStopJobSer = "StopJobService";
public String strKeyStSpJobSer;


@Override
public boolean onStartJob(JobParameters params) {
    i=1;

    doBackgroundWork(params);
    //Log.d ("FinishdoBackgroaund","Finish doBackgroaund work");
    return false;
}
   



public void doBackgroundWork(JobParameters params){
    try {
        ClipboardManager clipboardPaste = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        Date currentDate = new Date();
        clipTime = dateFormat.format(currentDate);
        ClipData clip = ClipData.newPlainText("Copy", "Job Start From Component  : " + clipTime);
        clipboardPaste.setPrimaryClip(clip);
        //Log.d("JobServiceStart", " : " + dateFormat.format(currentDate));
    }  catch (NullPointerException ignored) {
    }

}

@Override
public boolean onStopJob(JobParameters params) {
    Log.d("JobCanceeled","Job Cancelled");
    //jobcancelled=true;
    //doBackgroundWork(params);
    //return true;
    try {
        ClipboardManager clipboardPaste = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        Date currentDate = new Date();
        clipTime = dateFormat.format(currentDate);
        ClipData clip = ClipData.newPlainText("Copy", "Job Stopped : " + clipTime);
        clipboardPaste.setPrimaryClip(clip);
        Log.d("ServiceCurrentTime",  "Job Stopped : " + dateFormat.format(currentDate));
    } catch (NullPointerException ignored) {

    }


    return false;
}

}

Are you testing your project using the Appinventor companion? So you should test in a compiled APK, since the companion doesn't declare the services that your extension is using, also, if you are using kodular to test your extension, so the declared services would be ignored when writing the Android manifest, because of the fact, kodular still doesn't support UsesServices annotation.

1 Like

Thanks, for Reply

I am testing extension in a compiled APK develop in kodular.
Are JobService, Job Scheduler implemented in Extensions ?

If you want to use Services in apps built with Kodular, check out Rush. It allows you to use all the manifest tags that are contained in the <application> tag, and works with both AI2 and Kodular. Also, you don't need to use annotations like @UsesServices when you build your extension with Rush, since it provides out-of-the-box support for AndroidManifest.xml.

3 Likes

I face the same problem. I have added permission and I still face the problem in the compiled app too. Exported element is enabled to exported="true".

android.permission.BIND_JOB_SERVICE

edit: its the naming issue maybe

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.