
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.
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
| Table | Purpose |
|---|---|
sys_sg_mobile_app | Mobile app configs |
sys_sg_screen | Mobile screens |
sys_sg_card_builder | Card builders |
sys_push_notification | Push configs |
sys_sg_offline_rule | Offline 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
| Tool | Purpose |
|---|---|
snow_query_table | Query mobile configs |
snow_execute_script_with_output | Test mobile scripts |
snow_find_artifact | Find 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
- Offline First - Design for connectivity issues
- Minimal Data - Sync only necessary fields
- Push Wisely - Don't overwhelm with notifications
- Native Features - Use camera, GPS, barcode
- Card Design - Key info at a glance
- Performance - Optimize for mobile
- Testing - Test on actual devices
- ES5 Only - No modern JavaScript syntax
Score
Total Score
Based on repository quality metrics
SKILL.mdใใกใคใซใๅซใพใใฆใใ
ใฉใคใปใณในใ่จญๅฎใใใฆใใ
100ๆๅญไปฅไธใฎ่ชฌๆใใใ
GitHub Stars 100ไปฅไธ
1ใถๆไปฅๅ ใซๆดๆฐ
10ๅไปฅไธใใฉใผใฏใใใฆใใ
ใชใผใใณIssueใ50ๆชๆบ
ใใญใฐใฉใใณใฐ่จ่ชใ่จญๅฎใใใฆใใ
1ใคไปฅไธใฎใฟใฐใ่จญๅฎใใใฆใใ
Reviews
Reviews coming soon


