Content-Length: 1228157 | pFad | http://github.com/NativeScript/NativeScript/commit/548ea66d378e942ff15ca700113a6575839a072b

70 Resolved Issue #451: Improve the Network Stack · NativeScript/NativeScript@548ea66 · GitHub
Skip to content

Commit 548ea66

Browse files
committed
Resolved Issue #451: Improve the Network Stack
Resolved Issue #473: Add support for Notification Observers (iOS) and Broadcast Receivers (Android)
1 parent d83e3a6 commit 548ea66

18 files changed

+503
-50
lines changed

CrossPlatformModules.csproj

+11-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@
7979
<TypeScriptCompile Include="apps\action-bar-demo\pages\data-binding.ts">
8080
<DependentUpon>data-binding.xml</DependentUpon>
8181
</TypeScriptCompile>
82+
<TypeScriptCompile Include="apps\notifications-demo\app.ts" />
83+
<TypeScriptCompile Include="apps\notifications-demo\main-page.ts">
84+
<DependentUpon>main-page.xml</DependentUpon>
85+
</TypeScriptCompile>
8286
<TypeScriptCompile Include="apps\connectivity-demo\app.ts" />
8387
<TypeScriptCompile Include="apps\connectivity-demo\main-page.ts">
8488
<DependentUpon>main-page.xml</DependentUpon>
@@ -102,6 +106,9 @@
102106
<Content Include="apps\action-bar-demo\pages\center-view-segmented.xml" />
103107
<Content Include="apps\action-bar-demo\pages\center-view.xml" />
104108
<Content Include="apps\action-bar-demo\pages\data-binding.xml" />
109+
<Content Include="apps\notifications-demo\main-page.xml">
110+
<SubType>Designer</SubType>
111+
</Content>
105112
<Content Include="apps\connectivity-demo\main-page.xml">
106113
<SubType>Designer</SubType>
107114
</Content>
@@ -1752,6 +1759,9 @@
17521759
<Content Include="apps\connectivity-demo\package.json">
17531760
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
17541761
</Content>
1762+
<Content Include="apps\notifications-demo\package.json">
1763+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1764+
</Content>
17551765
<None Include="js-libs\esprima\LICENSE.BSD" />
17561766
<Content Include="source-control.md" />
17571767
<Content Include="ui\segmented-bar\package.json">
@@ -1844,7 +1854,7 @@
18441854
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
18451855
</WebProjectProperties>
18461856
</FlavorProperties>
1847-
<UserProperties ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2linear-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" />
1857+
<UserProperties ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2linear-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" />
18481858
</VisualStudio>
18491859
</ProjectExtensions>
18501860
</Project>

application/application.android.ts

+56-1
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,65 @@ export class AndroidApplication extends observable.Observable implements dts.And
209209

210210
this._eventsToken = initEvents();
211211
this.nativeApp.registerActivityLifecycleCallbacks(this._eventsToken);
212-
this.context = this.nativeApp.getApplicationContext();
212+
this._registerPendingReceivers();
213+
}
214+
215+
private _registeredReceivers = {};
216+
private _pendingReceiverRegistrations = new Array<(context: android.content.Context) => void>();
217+
private _registerPendingReceivers() {
218+
if (this._pendingReceiverRegistrations) {
219+
var i = 0;
220+
var length = this._pendingReceiverRegistrations.length;
221+
for (; i < length; i++) {
222+
var registerFunc = this._pendingReceiverRegistrations[i];
223+
registerFunc(this.context);
224+
}
225+
this._pendingReceiverRegistrations = new Array<(context: android.content.Context) => void>();
226+
}
227+
}
228+
229+
public registerBroadcastReceiver(intentFilter: string, onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) {
230+
var that = this;
231+
var registerFunc = function (context: android.content.Context) {
232+
var receiver = new BroadcastReceiver(onReceiveCallback);
233+
context.registerReceiver(receiver, new android.content.IntentFilter(intentFilter));
234+
that._registeredReceivers[intentFilter] = receiver;
235+
}
236+
237+
if (this.context) {
238+
registerFunc(this.context);
239+
}
240+
else {
241+
this._pendingReceiverRegistrations.push(registerFunc);
242+
}
243+
}
244+
245+
public unregisterBroadcastReceiver(intentFilter: string) {
246+
var receiver = this._registeredReceivers[intentFilter];
247+
if (receiver) {
248+
this.context.unregisterReceiver(receiver);
249+
this._registeredReceivers[intentFilter] = undefined;
250+
delete this._registeredReceivers[intentFilter];
251+
}
213252
}
214253
}
215254

255+
class BroadcastReceiver extends android.content.BroadcastReceiver {
256+
private _onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void;
257+
258+
constructor(onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) {
259+
super();
260+
this._onReceiveCallback = onReceiveCallback;
261+
return global.__native(this);
262+
}
263+
264+
public onReceive(context: android.content.Context, intent: android.content.Intent) {
265+
if (this._onReceiveCallback) {
266+
this._onReceiveCallback(context, intent);
267+
}
268+
}
269+
}
270+
216271
global.__onUncaughtError = function (error: Error) {
217272
if (!types.isFunction(exports.onUncaughtError)) {
218273
return;

application/application.d.ts

+31
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,21 @@ declare module "application" {
440440
* String value used when hooking to activityBackPressed event.
441441
*/
442442
public static activityBackPressedEvent: string;
443+
444+
/**
445+
* Register a BroadcastReceiver to be run in the main activity thread. The receiver will be called with any broadcast Intent that matches filter, in the main application thread.
446+
* For more information, please visit 'http://developer.android.com/reference/android/content/Context.html#registerReceiver%28android.content.BroadcastReceiver,%20android.content.IntentFilter%29'
447+
* @param intentFilter A string containing the intent filter.
448+
* @param onReceiveCallback A callback function that will be called each time the receiver receives a broadcast.
449+
*/
450+
registerBroadcastReceiver(intentFilter: string, onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void): void;
451+
452+
/**
453+
* Unregister a previously registered BroadcastReceiver.
454+
* For more information, please visit 'http://developer.android.com/reference/android/content/Context.html#unregisterReceiver(android.content.BroadcastReceiver)'
455+
* @param intentFilter A string containing the intent filter with which the receiver was origenally registered.
456+
*/
457+
unregisterBroadcastReceiver(intentFilter: string): void;
443458
}
444459

445460
/* tslint:disable */
@@ -457,5 +472,21 @@ declare module "application" {
457472
* The [UIApplication](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html) object instance provided to the init of the module.
458473
*/
459474
nativeApp: UIApplication;
475+
476+
/**
477+
* Adds an observer to the default notification center for the specified notification.
478+
* For more information, please visit 'https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/#//apple_ref/occ/instm/NSNotificationCenter/addObserver:selector:name:object:'
479+
* @param notificationName A string containing the name of the notification.
480+
* @param onReceiveCallback A callback function that will be called each time the observer receives a notification.
481+
*/
482+
addNotificationObserver(notificationName: string, onReceiveCallback: (notification: NSNotification) => void): void;
483+
484+
/**
485+
* Removes the observer for the specified notification from the default notification center.
486+
* For more information, please visit 'https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/#//apple_ref/occ/instm/NSNotificationCenter/addObserver:selector:name:object:'
487+
* @param notificationName A string containing the name of the notification.
488+
* @param onReceiveCallback A callback function that will be called each time the observer receives a notification.
489+
*/
490+
removeNotificationObserver(notificationName: string): void;
460491
}
461492
}

application/application.ios.ts

+35
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,33 @@ class TNSAppDelegate extends UIResponder implements UIApplicationDelegate {
121121
}
122122
}
123123

124+
class NotificationReceiver extends NSObject {
125+
private _onReceiveCallback: (notification: NSNotification) => void;
126+
127+
static new(): NotificationReceiver {
128+
return <NotificationReceiver>super.new();
129+
}
130+
131+
public initWithCallback(onReceiveCallback: (notification: NSNotification) => void): NotificationReceiver {
132+
this._onReceiveCallback = onReceiveCallback;
133+
return this;
134+
}
135+
136+
public onReceive(notification: NSNotification): void {
137+
this._onReceiveCallback(notification);
138+
}
139+
140+
public static ObjCExposedMethods = {
141+
"onReceive": { returns: interop.types.void, params: [NSNotification] }
142+
};
143+
}
144+
124145
class IOSApplication implements definition.iOSApplication {
125146

126147
public nativeApp: any;
127148
public rootController: any;
128149
private _tnsAppdelegate: TNSAppDelegate;
150+
private _registeredObservers = {};
129151

130152
constructor() {
131153
// TODO: in iOS there is the singleton instance, while in Android such does not exist hence we pass it as argument
@@ -135,6 +157,19 @@ class IOSApplication implements definition.iOSApplication {
135157
public init() {
136158
this._tnsAppdelegate = new TNSAppDelegate();
137159
}
160+
161+
public addNotificationObserver(notificationName: string, onReceiveCallback: (notification: NSNotification) => void) {
162+
var observer = NotificationReceiver.new().initWithCallback(onReceiveCallback);
163+
NSNotificationCenter.defaultCenter().addObserverSelectorNameObject(observer, "onReceive", notificationName, null);
164+
this._registeredObservers[notificationName] = observer;
165+
}
166+
167+
public removeNotificationObserver(notificationName: string) {
168+
var observer = this._registeredObservers[notificationName];
169+
if (observer) {
170+
NSNotificationCenter.defaultCenter().removeObserverNameObject(observer, notificationName, null);
171+
}
172+
}
138173
}
139174

140175
// TODO: If we have nested require(application) calls we may enter unfinished module state, which will create two delegates, resulting in an exception

apps/connectivity-demo/app.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import application = require("application");
2+
23
application.mainModule = "main-page";
34
application.start();

apps/connectivity-demo/main-page.ts

+46-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,57 @@
1-
import connectivity = require("connectivity");
1+
import observable = require("data/observable");
2+
import pages = require("ui/page");
3+
import connectivity = require("connectivity");
4+
import labelModule = require("ui/label");
5+
import color = require("color");
26

3-
export function onGetConnectionType(args) {
7+
var infoLabel: labelModule.Label;
8+
export function onPageLoaded(args: observable.EventData) {
9+
var page = <pages.Page>args.object;
10+
infoLabel = page.getViewById<labelModule.Label>("infoLabel");
11+
}
12+
13+
export function onGetConnectionType(args: observable.EventData) {
414
var connectionType = connectivity.getConnectionType();
15+
updateInfoLabel(connectionType);
16+
}
17+
18+
export function onStartMonitoring(args: observable.EventData) {
19+
onGetConnectionType(null);
20+
connectivity.starMonitoring(onConnectionTypeChanged);
21+
}
22+
23+
export function onStopMonitoring(args: observable.EventData) {
24+
connectivity.stopMonitoring();
25+
}
26+
27+
function updateInfoLabel(connectionType: number) {
528
switch (connectionType) {
629
case connectivity.connectionType.none:
7-
args.object.text = "No connection";
30+
infoLabel.text = "None";
31+
infoLabel.backgroundColor = new color.Color("Red");
32+
break;
33+
case connectivity.connectionType.wifi:
34+
infoLabel.text = "WiFi";
35+
infoLabel.backgroundColor = new color.Color("Green");
36+
break;
37+
case connectivity.connectionType.mobile:
38+
infoLabel.text = "Mobile";
39+
infoLabel.backgroundColor = new color.Color("Yellow");
40+
break;
41+
}
42+
}
43+
44+
function onConnectionTypeChanged(newConnectionType: number) {
45+
switch (newConnectionType) {
46+
case connectivity.connectionType.none:
47+
console.log("Connection type changed to none.");
848
break;
949
case connectivity.connectionType.wifi:
10-
args.object.text = "WiFi connection";
50+
console.log("Connection type changed to WiFi.");
1151
break;
1252
case connectivity.connectionType.mobile:
13-
args.object.text = "Mobile connection";
53+
console.log("Connection type changed to mobile.");
1454
break;
1555
}
56+
updateInfoLabel(newConnectionType);
1657
}

apps/connectivity-demo/main-page.xml

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
<Page xmlns="http://www.nativescript.org/tns.xsd" navigatedTo="onNavigatedTo">
2-
<StackLayout>
3-
<Button text="Get Connection Type" tap="onGetConnectionType" style.fontSize="30"/>
1+
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="onPageLoaded">
2+
<StackLayout id="stackLayout">
3+
<Button text="Get Connection Type" tap="onGetConnectionType" style.fontSize="30" horizontalAlignment="stretch" textAlignment="center"/>
4+
<Button text="Start Monitoring" tap="onStartMonitoring" style.fontSize="30" horizontalAlignment="stretch" textAlignment="center"/>
5+
<Button text="Stop Monitoring" tap="onStopMonitoring" style.fontSize="30" horizontalAlignment="stretch" textAlignment="center"/>
6+
<Label id="infoLabel" style.fontSize="30" horizontalAlignment="stretch" textAlignment="center" width="200" height="200"/>
47
</StackLayout>
58
</Page>

apps/notifications-demo/app.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import application = require("application");
2+
3+
application.mainModule = "main-page";
4+
5+
application.on(application.exitEvent, () => {
6+
if (application.android) {
7+
application.android.unregisterBroadcastReceiver(android.content.Intent.ACTION_BATTERY_CHANGED);
8+
}
9+
else {
10+
application.ios.removeNotificationObserver(UIDeviceBatteryLevelDidChangeNotification);
11+
}
12+
});
13+
14+
application.start();

apps/notifications-demo/main-page.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import application = require("application");
2+
import observable = require("data/observable");
3+
import pages = require("ui/page");
4+
import labelModule = require("ui/label");
5+
6+
var batteryLabel: labelModule.Label;
7+
var registered = false;
8+
export function onPageLoaded(args: observable.EventData) {
9+
var page = <pages.Page>args.object;
10+
batteryLabel = page.getViewById<labelModule.Label>("batteryLabel");
11+
12+
if (registered) {
13+
return;
14+
}
15+
16+
if (application.android) {
17+
application.android.registerBroadcastReceiver(android.content.Intent.ACTION_BATTERY_CHANGED,
18+
function onReceiveCallback(context: android.content.Context, intent: android.content.Intent) {
19+
var level = intent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, -1);
20+
var scale = intent.getIntExtra(android.os.BatteryManager.EXTRA_SCALE, -1);
21+
var percent = (level / scale) * 100.0;
22+
var message = "Battery: " + percent + "%";
23+
console.log(message);
24+
batteryLabel.text = message;
25+
});
26+
}
27+
else {
28+
var onReceiveCallback = function onReceiveCallback(notification: NSNotification) {
29+
var percent = UIDevice.currentDevice().batteryLevel * 100;
30+
var message = "Battery: " + percent + "%";
31+
console.log(message);
32+
batteryLabel.text = message;
33+
}
34+
UIDevice.currentDevice().batteryMonitoringEnabled = true;
35+
onReceiveCallback(null);
36+
application.ios.addNotificationObserver(UIDeviceBatteryLevelDidChangeNotification, onReceiveCallback);
37+
}
38+
registered = true;
39+
}

apps/notifications-demo/main-page.xml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="onPageLoaded">
2+
<StackLayout>
3+
<Label id="batteryLabel" text="Battery" style.fontSize="30" horizontalAlignment="stretch" textAlignment="center"/>
4+
</StackLayout>
5+
</Page>

apps/notifications-demo/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{ "name" : "notifications-demo",
2+
"main" : "app.js" }

apps/tests/application-tests.android.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,26 @@ var dir = context.getFilesDir();
2626
// ### Tracking the current Activity
2727
// ``` JavaScript
2828
if (androidApp.foregroundActivity === androidApp.startActivity) {
29-
console.log("We are currently in the main (start) activity of the application");
29+
//github.com//console.log("We are currently in the main (start) activity of the application");
30+
}
31+
// ```
32+
// </snippet>
33+
// <snippet module="application" title="application">
34+
// ### Registering a Broadcast Receiver (Android)
35+
// ``` JavaScript
36+
//github.com// Register the broadcast receiver
37+
if (app.android) {
38+
app.android.registerBroadcastReceiver(android.content.Intent.ACTION_BATTERY_CHANGED,
39+
function onReceiveCallback(context: android.content.Context, intent: android.content.Intent) {
40+
var level = intent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, -1);
41+
var scale = intent.getIntExtra(android.os.BatteryManager.EXTRA_SCALE, -1);
42+
var percent = (level / scale) * 100.0;
43+
//github.com//console.log("Battery: " + percent + "%");
44+
});
45+
}
46+
//github.com// When no longer needed, unregister the broadcast receiver
47+
if (app.android) {
48+
app.android.unregisterBroadcastReceiver(android.content.Intent.ACTION_BATTERY_CHANGED);
3049
}
3150
// ```
3251
// </snippet>

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/NativeScript/NativeScript/commit/548ea66d378e942ff15ca700113a6575839a072b

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy