โ† Back to list
groeimetai

mobile-development

by groeimetai

๐Ÿค– AI-powered ServiceNow development with 400+ MCP tools. Works with Claude, GPT, Gemini, Ollama & 75+ providers. Deploy widgets, manage incidents, automate workflows - all through natural language. Open-source Build Agent alternative.

โญ 42๐Ÿด 9๐Ÿ“… Jan 23, 2026

SKILL.md


name: mobile-development description: This skill should be used when the user asks to "mobile app", "mobile studio", "push notification", "offline", "mobile card", "native mobile", "mobile UI", or any ServiceNow Mobile development. license: Apache-2.0 compatibility: Designed for Snow-Code and ServiceNow development metadata: author: groeimetai version: "1.0.0" category: servicenow tools:

  • snow_query_table
  • snow_execute_script_with_output
  • snow_find_artifact

Mobile Development for ServiceNow

Mobile development enables native mobile experiences with offline capabilities.

Mobile Architecture

Mobile App Configuration
    โ”œโ”€โ”€ App Screens
    โ”‚   โ”œโ”€โ”€ List Views
    โ”‚   โ”œโ”€โ”€ Detail Views
    โ”‚   โ””โ”€โ”€ Card Builders
    โ”œโ”€โ”€ Push Notifications
    โ”œโ”€โ”€ Offline Rules
    โ””โ”€โ”€ Mobile Actions

Key Tables

TablePurpose
sys_sg_mobile_appMobile app configs
sys_sg_screenMobile screens
sys_sg_card_builderCard builders
sys_push_notificationPush configs
sys_sg_offline_ruleOffline rules

Mobile App Configuration (ES5)

Create Mobile App

// Create mobile app configuration (ES5 ONLY!)
var app = new GlideRecord('sys_sg_mobile_app');
app.initialize();

app.setValue('name', 'IT Support');
app.setValue('description', 'Mobile app for IT support tasks');

// App settings
app.setValue('active', true);
app.setValue('version', '1.0.0');

// Branding
app.setValue('primary_color', '#1976D2');
app.setValue('secondary_color', '#FFFFFF');
app.setValue('icon', 'attachment_sys_id');

// Default screen
app.setValue('home_screen', homeScreenSysId);

// Roles
app.setValue('roles', 'itil');

app.insert();

Configure Mobile Screen

// Create mobile screen (ES5 ONLY!)
var screen = new GlideRecord('sys_sg_screen');
screen.initialize();

screen.setValue('name', 'My Incidents');
screen.setValue('mobile_app', mobileAppSysId);
screen.setValue('type', 'list');  // list, record, custom

// Data source
screen.setValue('table', 'incident');
screen.setValue('filter', 'assigned_to=javascript:gs.getUserID()^active=true');

// Display
screen.setValue('title', 'My Incidents');
screen.setValue('icon', 'list');

// Ordering
screen.setValue('order', 100);

screen.insert();

Card Builder (ES5)

Create Card Configuration

// Create card builder for list display (ES5 ONLY!)
var card = new GlideRecord('sys_sg_card_builder');
card.initialize();

card.setValue('name', 'Incident Card');
card.setValue('table', 'incident');

// Card layout
card.setValue('primary_field', 'number');
card.setValue('secondary_field', 'short_description');
card.setValue('tertiary_field', 'priority');

// Additional fields
card.setValue('fields', JSON.stringify([
    { field: 'caller_id', label: 'Caller' },
    { field: 'state', label: 'Status' },
    { field: 'opened_at', label: 'Opened' }
]));

// Visual indicators
card.setValue('color_field', 'priority');
card.setValue('color_mapping', JSON.stringify({
    '1': '#D32F2F',  // Critical - Red
    '2': '#F57C00',  // High - Orange
    '3': '#FBC02D',  // Moderate - Yellow
    '4': '#388E3C',  // Low - Green
    '5': '#1976D2'   // Planning - Blue
}));

card.insert();

Custom Card Actions

// Add actions to card (ES5 ONLY!)
function addCardAction(cardSysId, actionDef) {
    var action = new GlideRecord('sys_sg_card_action');
    action.initialize();

    action.setValue('card_builder', cardSysId);
    action.setValue('label', actionDef.label);
    action.setValue('icon', actionDef.icon);
    action.setValue('order', actionDef.order);

    // Action type
    action.setValue('action_type', actionDef.type);  // script, navigate, share

    // Script action (ES5 ONLY!)
    if (actionDef.type === 'script') {
        action.setValue('script', actionDef.script);
    }

    action.insert();
}

// Example actions
addCardAction(cardSysId, {
    label: 'Acknowledge',
    icon: 'check',
    order: 100,
    type: 'script',
    script:
        '(function(gr) {\n' +
        '    gr.state = 2;  // In Progress\n' +
        '    gr.work_notes = "Acknowledged via mobile";\n' +
        '    gr.update();\n' +
        '    gs.addInfoMessage("Incident acknowledged");\n' +
        '})(current);'
});

Push Notifications (ES5)

Configure Push Notification

// Create push notification config (ES5 ONLY!)
var push = new GlideRecord('sys_push_notification');
push.initialize();

push.setValue('name', 'High Priority Incident Assigned');
push.setValue('description', 'Notify when high priority incident assigned');

// Target table and condition
push.setValue('table', 'incident');
push.setValue('condition', 'priority<=2^assigned_to.changes()');

// Notification content
push.setValue('title', 'High Priority Incident Assigned');
push.setValue('body', '${number}: ${short_description}');

// Recipients
push.setValue('recipient_type', 'field');
push.setValue('recipient_field', 'assigned_to');

// Deep link
push.setValue('deep_link', true);
push.setValue('link_url', '/incident/${sys_id}');

push.setValue('active', true);

push.insert();

Send Push Notification Programmatically

// Send push notification (ES5 ONLY!)
function sendPushNotification(userSysId, message) {
    try {
        var push = new sn_notification.PushNotification();

        push.setTitle(message.title);
        push.setBody(message.body);

        if (message.data) {
            push.setData(message.data);
        }

        if (message.deepLink) {
            push.setDeepLink(message.deepLink);
        }

        push.send(userSysId);

        return { success: true };
    } catch (e) {
        gs.error('Push notification failed: ' + e.message);
        return { success: false, error: e.message };
    }
}

// Example
sendPushNotification(userSysId, {
    title: 'Task Assigned',
    body: 'You have a new task assigned',
    deepLink: '/task/' + taskSysId
});

Offline Capabilities (ES5)

Configure Offline Rules

// Create offline sync rule (ES5 ONLY!)
var rule = new GlideRecord('sys_sg_offline_rule');
rule.initialize();

rule.setValue('name', 'My Open Incidents');
rule.setValue('mobile_app', mobileAppSysId);
rule.setValue('table', 'incident');

// Sync filter
rule.setValue('filter', 'assigned_to=javascript:gs.getUserID()^active=true');

// Fields to sync
rule.setValue('fields', 'number,short_description,description,priority,state,caller_id,opened_at');

// Related records
rule.setValue('include_references', true);
rule.setValue('reference_fields', 'caller_id,assignment_group');

// Sync limits
rule.setValue('max_records', 100);

// Update frequency
rule.setValue('sync_frequency', 'on_demand');  // on_demand, periodic

rule.setValue('active', true);

rule.insert();

Handle Offline Data

// Check for offline changes on sync (ES5 ONLY!)
function processOfflineChanges(userId) {
    var offlineQueue = new GlideRecord('sys_sg_offline_queue');
    offlineQueue.addQuery('user', userId);
    offlineQueue.addQuery('processed', false);
    offlineQueue.orderBy('created_on');
    offlineQueue.query();

    var results = { processed: 0, errors: [] };

    while (offlineQueue.next()) {
        try {
            var tableName = offlineQueue.getValue('table');
            var recordSysId = offlineQueue.getValue('record');
            var changes = JSON.parse(offlineQueue.getValue('changes'));

            // Apply changes
            var gr = new GlideRecord(tableName);
            if (gr.get(recordSysId)) {
                for (var field in changes) {
                    if (changes.hasOwnProperty(field)) {
                        gr.setValue(field, changes[field]);
                    }
                }
                gr.update();
                results.processed++;
            }

            // Mark as processed
            offlineQueue.processed = true;
            offlineQueue.update();

        } catch (e) {
            results.errors.push({
                record: offlineQueue.getValue('record'),
                error: e.message
            });
        }
    }

    return results;
}

Mobile Actions (ES5)

Create Mobile Action

// Create mobile-specific action (ES5 ONLY!)
var action = new GlideRecord('sys_sg_action');
action.initialize();

action.setValue('name', 'Scan Barcode');
action.setValue('label', 'Scan Asset');
action.setValue('description', 'Scan barcode to find asset');

// Action type
action.setValue('type', 'native');  // native, script, link
action.setValue('native_action', 'barcode_scan');

// Available on
action.setValue('screens', screenSysIds);

// Callback script (ES5 ONLY!)
action.setValue('callback_script',
    '(function(result) {\n' +
    '    if (!result.value) return;\n' +
    '    \n' +
    '    var asset = new GlideRecord("alm_asset");\n' +
    '    asset.addQuery("asset_tag", result.value);\n' +
    '    asset.query();\n' +
    '    \n' +
    '    if (asset.next()) {\n' +
    '        // Navigate to asset\n' +
    '        sn_mobile.navigate("record", {\n' +
    '            table: "alm_asset",\n' +
    '            sys_id: asset.getUniqueValue()\n' +
    '        });\n' +
    '    } else {\n' +
    '        gs.addErrorMessage("Asset not found: " + result.value);\n' +
    '    }\n' +
    '})(scanResult);'
);

action.insert();

Location-Based Action

// Get user location for mobile (ES5 ONLY!)
// Available in mobile context

function getCurrentLocation() {
    try {
        var location = sn_mobile.getLocation();
        return {
            latitude: location.latitude,
            longitude: location.longitude,
            accuracy: location.accuracy
        };
    } catch (e) {
        return null;
    }
}

// Use location for nearby assets
function findNearbyAssets(latitude, longitude, radiusMeters) {
    var assets = [];

    var gr = new GlideRecord('alm_asset');
    gr.addNotNullQuery('location.latitude');
    gr.query();

    while (gr.next()) {
        var assetLat = parseFloat(gr.location.latitude);
        var assetLon = parseFloat(gr.location.longitude);

        var distance = calculateDistance(latitude, longitude, assetLat, assetLon);

        if (distance <= radiusMeters) {
            assets.push({
                sys_id: gr.getUniqueValue(),
                name: gr.getDisplayValue(),
                distance: Math.round(distance)
            });
        }
    }

    return assets.sort(function(a, b) {
        return a.distance - b.distance;
    });
}

MCP Tool Integration

Available Tools

ToolPurpose
snow_query_tableQuery mobile configs
snow_execute_script_with_outputTest mobile scripts
snow_find_artifactFind configurations

Example Workflow

// 1. Query mobile apps
await snow_query_table({
    table: 'sys_sg_mobile_app',
    query: 'active=true',
    fields: 'name,description,version,roles'
});

// 2. Get push notification configs
await snow_query_table({
    table: 'sys_push_notification',
    query: 'active=true',
    fields: 'name,table,condition,title'
});

// 3. Check offline rules
await snow_query_table({
    table: 'sys_sg_offline_rule',
    query: 'active=true',
    fields: 'name,table,filter,max_records'
});

Best Practices

  1. Offline First - Design for connectivity issues
  2. Minimal Data - Sync only necessary fields
  3. Push Wisely - Don't overwhelm with notifications
  4. Native Features - Use camera, GPS, barcode
  5. Card Design - Key info at a glance
  6. Performance - Optimize for mobile
  7. Testing - Test on actual devices
  8. ES5 Only - No modern JavaScript syntax

Score

Total Score

75/100

Based on repository quality metrics

โœ“SKILL.md

SKILL.mdใƒ•ใ‚กใ‚คใƒซใŒๅซใพใ‚Œใฆใ„ใ‚‹

+20
โœ“LICENSE

ใƒฉใ‚คใ‚ปใƒณใ‚นใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+10
โœ“่ชฌๆ˜Žๆ–‡

100ๆ–‡ๅญ—ไปฅไธŠใฎ่ชฌๆ˜ŽใŒใ‚ใ‚‹

+10
โ—‹ไบบๆฐ—

GitHub Stars 100ไปฅไธŠ

0/15
โœ“ๆœ€่ฟ‘ใฎๆดปๅ‹•

1ใƒถๆœˆไปฅๅ†…ใซๆ›ดๆ–ฐ

+10
โ—‹ใƒ•ใ‚ฉใƒผใ‚ฏ

10ๅ›žไปฅไธŠใƒ•ใ‚ฉใƒผใ‚ฏใ•ใ‚Œใฆใ„ใ‚‹

0/5
โœ“Issue็ฎก็†

ใ‚ชใƒผใƒ—ใƒณIssueใŒ50ๆœชๆบ€

+5
โœ“่จ€่ชž

ใƒ—ใƒญใ‚ฐใƒฉใƒŸใƒณใ‚ฐ่จ€่ชžใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+5
โœ“ใ‚ฟใ‚ฐ

1ใคไปฅไธŠใฎใ‚ฟใ‚ฐใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+5

Reviews

๐Ÿ’ฌ

Reviews coming soon