Token导航 LogoToken导航

Agent Skill · 待分类

workmanager(workmanager 命令行)

workmanager 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

workmanager 是待分类类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描有提醒项,按安装量在待分类类的 11,209 个 Skill 里排第 7,063。

总安装 392周安装 16GitHub Stars 2下载 125核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:workmanager(workmanager 命令行)
来源仓库:https://github.com/andvl1/claude-plugin
仓库路径:skills/workmanager
安装命令:
npx skills add https://github.com/andvl1/claude-plugin --skill workmanager
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/andvl1/claude-plugin --skill workmanager

这个 Skill 是做什么的

这个 Skill 的分类还没最终确定,用法以来源仓库的说明为准。

workmanager 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。

安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/workmanager

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/andvl1/claude-plugin --skill workmanager;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

workmanager 怎么安装?

在终端执行 npx skills add https://github.com/andvl1/claude-plugin --skill workmanager。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

workmanager 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

workmanager 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

workmanager 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

workmanager 用的人多吗?

公开数据是累计安装 392 次,近一周安装 16 次,下载 125 次,GitHub 2 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

workmanager 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理待分类类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

待分类类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
infsh-cli

infsh CLI · Codex、Claude

4,374,576382权限未标注未明确未收录
ai-video-generation

AI 视频生成 · Codex、Claude

4,313,376382调用外部服务未明确有提醒
lark-openapi-explorer

云雀 OpenAPI 浏览器 · Codex、Claude

2,064,1209,011需要联网未明确有提醒
lark-workflow-standup-report

Lark 工作流程站立报告 · Codex、Claude

2,041,6328,978需要联网未明确通过
use-my-browser

使用我的浏览器 · Codex、Claude

1,848,49140操作浏览器未明确未通过
workmanager

workmanager 命令行 · 本页

3922需要联网未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Android WorkManager

WorkManager is the recommended solution for persistent, guaranteed background work on Android.

When to Use WorkManager

Use WorkManager for:

  • Periodic background sync - Sync data with server every 15+ minutes
  • Deferred tasks - Upload files, compress images when device is ready
  • Guaranteed execution - Tasks that must run even if app is killed
  • Constraint-based work - Run only when WiFi connected, battery charging, etc.

Don't use WorkManager for:

  • Immediate execution - Use Kotlin coroutines directly
  • Precise timing - Use AlarmManager for exact scheduling
  • Foreground work - Use coroutines in ViewModel/Service

Dependencies

// build.gradle.kts (androidMain or Android module)
dependencies {
    implementation("androidx.work:work-runtime-ktx:2.10.0")
}

CoroutineWorker Basics

Simple Worker

class SyncWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            // Perform background work
            val data = fetchDataFromServer()
            saveToDatabase(data)

            Result.success()
        } catch (e: Exception) {
            Log.e("SyncWorker", "Sync failed", e)

            if (runAttemptCount < 3) {
                Result.retry() // Retry with exponential backoff
            } else {
                Result.failure() // Give up after 3 attempts
            }
        }
    }
}

Worker with Input/Output Data

class UploadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        // Get input data
        val fileUri = inputData.getString(KEY_FILE_URI) ?: return Result.failure()
        val userId = inputData.getLong(KEY_USER_ID, -1L)

        return try {
            val uploadedUrl = uploadFile(fileUri)

            // Return output data
            val outputData = workDataOf(
                KEY_UPLOADED_URL to uploadedUrl,
                KEY_TIMESTAMP to System.currentTimeMillis()
            )

            Result.success(outputData)
        } catch (e: Exception) {
            Result.retry()
        }
    }

    companion object {
        const val KEY_FILE_URI = "file_uri"
        const val KEY_USER_ID = "user_id"
        const val KEY_UPLOADED_URL = "uploaded_url"
        const val KEY_TIMESTAMP = "timestamp"
    }
}

Worker with Progress

class DownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        val url = inputData.getString(KEY_URL) ?: return Result.failure()

        return try {
            downloadFile(url) { progress ->
                // Update progress (0-100)
                setProgress(workDataOf(KEY_PROGRESS to progress))
            }

            Result.success()
        } catch (e: Exception) {
            Result.failure()
        }
    }

    companion object {
        const val KEY_URL = "url"
        const val KEY_PROGRESS = "progress"
    }
}

// Observe progress
WorkManager.getInstance(context)
    .getWorkInfoByIdLiveData(workId)
    .observe(lifecycleOwner) { workInfo ->
        val progress = workInfo?.progress?.getInt(DownloadWorker.KEY_PROGRESS, 0) ?: 0
        updateProgressBar(progress)
    }

Foreground Worker (with Notification)

class LongRunningWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        // Show notification for long-running work
        setForeground(createForegroundInfo())

        return try {
            performLongOperation()
            Result.success()
        } catch (e: Exception) {
            Result.failure()
        }
    }

    private fun createForegroundInfo(): ForegroundInfo {
        val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
            .setContentTitle("Processing")
            .setContentText("Processing your request...")
            .setSmallIcon(R.drawable.ic_notification)
            .setOngoing(true)
            .build()

        return ForegroundInfo(NOTIFICATION_ID, notification)
    }

    companion object {
        private const val CHANNEL_ID = "work_channel"
        private const val NOTIFICATION_ID = 1
    }
}

Scheduling Work

One-Time Work

// Simple enqueue
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
    .build()

WorkManager.getInstance(context).enqueue(syncRequest)

// With input data
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(workDataOf(
        UploadWorker.KEY_FILE_URI to fileUri,
        UploadWorker.KEY_USER_ID to userId
    ))
    .build()

WorkManager.getInstance(context).enqueue(uploadRequest)

// With constraints (see Constraints section)
val constrainedRequest = OneTimeWorkRequestBuilder<SyncWorker>()
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()
    )
    .build()

WorkManager.getInstance(context).enqueue(constrainedRequest)

Periodic Work

// Minimum interval is 15 minutes
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
    repeatInterval = 15,
    repeatIntervalTimeUnit = TimeUnit.MINUTES
)
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()
    )
    .build()

WorkManager.getInstance(context).enqueue(syncRequest)

// With flex interval (run within last 5 minutes of 15-minute period)
val flexRequest = PeriodicWorkRequestBuilder<SyncWorker>(
    repeatInterval = 15,
    repeatIntervalTimeUnit = TimeUnit.MINUTES,
    flexTimeInterval = 5,
    flexTimeIntervalUnit = TimeUnit.MINUTES
)
    .build()

Delayed Work

val delayedRequest = OneTimeWorkRequestBuilder<NotificationWorker>()
    .setInitialDelay(1, TimeUnit.HOURS)
    .build()

WorkManager.getInstance(context).enqueue(delayedRequest)

Expedited Work (Android 12+)

// For important user-facing work
val expeditedRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

WorkManager.getInstance(context).enqueue(expeditedRequest)

Constraints

See references/constraints.md for detailed constraint patterns and combinations.

Quick reference:

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED) // Any network
    .setRequiresBatteryNotLow(true)
    .setRequiresCharging(false)
    .setRequiresStorageNotLow(true)
    .setRequiresDeviceIdle(false) // API 23+
    .build()

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    .setConstraints(constraints)
    .build()

Work Chaining

See references/chaining.md for advanced chaining patterns and parallel execution.

Sequential Chain

WorkManager.getInstance(context)
    .beginWith(downloadRequest)
    .then(processRequest)
    .then(uploadRequest)
    .enqueue()

Parallel Chains

val chain1 = WorkManager.getInstance(context).beginWith(work1A).then(work1B)
val chain2 = WorkManager.getInstance(context).beginWith(work2A).then(work2B)

val finalWork = OneTimeWorkRequestBuilder<FinalWorker>().build()

WorkContinuation.combine(listOf(chain1, chain2))
    .then(finalWork)
    .enqueue()

Unique Work

Replace Existing Work

WorkManager.getInstance(context)
    .enqueueUniqueWork(
        "daily_sync",
        ExistingWorkPolicy.REPLACE,
        syncRequest
    )

Keep Existing Work

WorkManager.getInstance(context)
    .enqueueUniqueWork(
        "upload_${fileId}",
        ExistingWorkPolicy.KEEP,
        uploadRequest
    )

Append to Existing Work

WorkManager.getInstance(context)
    .enqueueUniqueWork(
        "sync_chain",
        ExistingWorkPolicy.APPEND,
        newSyncRequest
    )

Unique Periodic Work

WorkManager.getInstance(context)
    .enqueueUniquePeriodicWork(
        "periodic_sync",
        ExistingPeriodicWorkPolicy.KEEP,
        periodicRequest
    )

Observing Work

By ID

WorkManager.getInstance(context)
    .getWorkInfoByIdLiveData(workRequest.id)
    .observe(lifecycleOwner) { workInfo ->
        when (workInfo?.state) {
            WorkInfo.State.ENQUEUED -> showStatus("Queued")
            WorkInfo.State.RUNNING -> showStatus("Running")
            WorkInfo.State.SUCCEEDED -> {
                showStatus("Success")
                val outputUrl = workInfo.outputData.getString(KEY_UPLOADED_URL)
                handleSuccess(outputUrl)
            }
            WorkInfo.State.FAILED -> showStatus("Failed")
            WorkInfo.State.BLOCKED -> showStatus("Blocked")
            WorkInfo.State.CANCELLED -> showStatus("Cancelled")
            null -> showStatus("Unknown")
        }
    }

By Tag

val request = OneTimeWorkRequestBuilder<SyncWorker>()
    .addTag("sync")
    .build()

WorkManager.getInstance(context)
    .getWorkInfosByTagLiveData("sync")
    .observe(lifecycleOwner) { workInfos ->
        val running = workInfos.count { it.state == WorkInfo.State.RUNNING }
        updateUI("$running sync tasks running")
    }

By Unique Name

WorkManager.getInstance(context)
    .getWorkInfosForUniqueWorkLiveData("daily_sync")
    .observe(lifecycleOwner) { workInfos ->
        // Handle work info list
    }

Using Flow (Coroutines)

WorkManager.getInstance(context)
    .getWorkInfoByIdFlow(workId)
    .collect { workInfo ->
        when (workInfo?.state) {
            WorkInfo.State.SUCCEEDED -> handleSuccess()
            WorkInfo.State.FAILED -> handleFailure()
            else -> {}
        }
    }

Cancelling Work

// Cancel by ID
WorkManager.getInstance(context).cancelWorkById(workId)

// Cancel by tag
WorkManager.getInstance(context).cancelAllWorkByTag("sync")

// Cancel by unique name
WorkManager.getInstance(context).cancelUniqueWork("daily_sync")

// Cancel all work
WorkManager.getInstance(context).cancelAllWork()

Testing

See references/testing.md for complete testing guide including TestWorkerFactory and WorkManagerTestInitHelper.

Quick test example:

@Test
fun testSyncWorker() = runTest {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val executor = Executors.newSingleThreadExecutor()

    WorkManagerTestInitHelper.initializeTestWorkManager(context)

    val worker = TestListenableWorkerBuilder<SyncWorker>(context).build()

    val result = worker.doWork()

    assertThat(result).isEqualTo(Result.success())
}

Dependency Injection

With Metro DI

// Define factory in DI graph
@ModuleScope
class WorkerFactory(
    private val syncRepository: SyncRepository,
    private val uploadService: UploadService
) : WorkerFactory() {

    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? {
        return when (workerClassName) {
            SyncWorker::class.java.name ->
                SyncWorker(appContext, workerParameters, syncRepository)

            UploadWorker::class.java.name ->
                UploadWorker(appContext, workerParameters, uploadService)

            else -> null
        }
    }
}

// In Application onCreate
class MyApplication : Application(), Configuration.Provider {

    private lateinit var workerFactory: WorkerFactory

    override fun onCreate() {
        super.onCreate()

        // Get factory from DI
        workerFactory = AppGraph.workerFactory
    }

    override val workManagerConfiguration: Configuration
        get() = Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
}

// Worker with dependencies
class SyncWorker(
    context: Context,
    params: WorkerParameters,
    private val repository: SyncRepository
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            repository.sync()
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

Important Limitations

Timing Constraints

  • Minimum periodic interval: 15 minutes
  • Flex interval: Must be >= 5 minutes and < repeat interval
  • Not for exact timing: WorkManager is not AlarmManager - execution time is approximate
  • Doze mode delays: Work can be significantly delayed when device is in doze mode

Execution Constraints

  • 10-minute execution limit: Workers should complete within 10 minutes
  • Background execution limits: Subject to Android's background execution limits
  • CoroutineWorker scope: Uses default Dispatchers.Default, not main thread
  • No guarantee of immediate execution: Work is scheduled optimally by system

Data Limitations

  • Input/Output data size: Limited to 10KB
  • Primitive types only: WorkData supports only primitives, arrays, and strings
  • No complex objects: Cannot pass custom objects directly
  • Use serialization: For complex data, serialize to JSON string or use file paths

Worker Lifecycle

  • Worker is recreated: Each execution creates a new Worker instance
  • No shared state: Cannot rely on instance variables between executions
  • Context is Application: Worker's context is always Application context, not Activity
  • RunAttemptCount: Increments on each retry, resets on success

Device and System Constraints

  • Battery optimization: Can be affected by manufacturer-specific battery optimizations
  • App standby buckets: Work frequency limited by app's standby bucket
  • Background restrictions: Some manufacturers aggressively kill background work
  • Requires Google Play Services: WorkManager relies on Google Play Services JobScheduler

Best Practices

Do's

  • Use CoroutineWorker for suspend functions
  • Set appropriate constraints for network/battery requirements
  • Use setBackoffCriteria() for custom retry strategies
  • Tag work requests for easier management
  • Use unique work names to prevent duplicate tasks
  • Return Result.retry() for transient failures
  • Implement proper error handling and logging
  • Use setForeground() for long-running work (>10 min)

Don'ts

  • Don't use WorkManager for immediate execution
  • Don't expect precise scheduling
  • Don't pass large data through WorkData (use file URIs)
  • Don't block main thread in Worker
  • Don't rely on Worker instance state
  • Don't schedule periodic work < 15 minutes
  • Don't forget to cancel work when no longer needed
  • Don't use for foreground services (use actual Service)

Troubleshooting

See references/troubleshooting.md for detailed solutions to common problems.

Common issues:

  • Work not executing
  • Constraints not working as expected
  • Work retrying indefinitely
  • DI not working in Workers
  • Testing failures

Resources

平台分布

Codex

34.85%
按下载量换算44

Claude

32.34%
按下载量换算40

Cursor

19.34%
按下载量换算24

Gemini CLI

9.9%
按下载量换算12

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills