NativeScript能夠用javascript來寫Android和iOS的應用,以下圖所示NativeScript的代碼與網頁開發的代碼很類似,都是用CSS寫樣式,javascript寫業務邏輯,不一樣的是NativeScript使用XML來描述頁面結構(NativeScript封裝了本身的UI庫)。 javascript
以下圖所示, 移動應用程序可分爲四大類:native, hybrid, cross compiled, and just-in-time (JIT) compiled css
讓咱們根據下圖一塊兒看一看不一樣類型的移動應用程序之間的差別以及它們如何在設備上運行 hybrid app本質上是在web瀏覽器中運行的網頁。cross compiled app經過編譯器被轉換成native app。而JIT compiled app(例如NativeScript)運行在一個 JavaScript的虛擬機裏。更少的shim代碼(處理Android和iOS的不一樣)、一次寫入(Android和iOS共用一套代碼)、隨處部署等等。html
由於NativeScript應用程序直接運行在設備上,並由運行在應用程序內部的JavaScript虛擬機解釋,這意味着NativeScript應用程序不受訪問本機設備api或硬件的限制,所以任何應用程序均可以編寫爲NativeScript應用。理論上是這樣的,可是NativeScript應用程序是在JavaScript虛擬機中運行的,因此在應用程序和裸機之間有一個額外的(儘管很小)抽象層。要從設備中提取每一點性能,因此它不適合構建圖形密集的遊戲。java
NativeScript Runtime
:NativeScript Runtime是鏈接JavaScript代碼和Android和iOS原生API之間的接口代碼。就像瀏覽器製造商教他們的JavaScript虛擬機如何使用DOM和windows對象同樣,NativeScript Runtime也教JavaScript虛擬機如何使用本機設備底層的API。NativeScript Core Modules
: NativeScriptCore Modules是一組庫,這些庫是用來構建應用程序並指示NativeScript運行時在設備上作什麼。核心模塊由不一樣的庫組成,如UI組件(按鈕、列表視圖、標籤)、導航和應用程序。JavaScript virtual machine
:理解並執行JavaScript的代碼,可是不知道怎麼與設備交互,因此NativeScript開發團隊編寫了接口代碼(稱爲NativeScript Runtime和NativeScript Core Modules)來教JavaScript虛擬機有關Android和iOS等移動設備API的知識。NativeScript CLI
:NativeScript CLI抽離了本地工具和SDK的複雜性,爲咱們提供了一組與平臺無關的命令來構建和部署應用程序。tns create HelloWorld --template tns-template-hello-world
cd [filename]
tns run android --emulator
,便可在Android模擬器上運行代碼|- app //開發目錄
|- App_Resources //放置Android和iOS平臺特殊的配置,例如App的圖標等。
|- Android
|- iOS
|- app.css //全局的CSS樣式,app運行時載入
|- app.js //啓動文件,裏面說明了從哪一個頁面啓動應用
|- bundle-config.js //用於配置webpack(若是已安裝了)
|- main-page.js //寫業務邏輯
|- main-page.xml //寫頁面代碼
|- main-view-model.js //至關於MVVM框架的vm層
|- package.json //描述應用程序的特徵和依賴項
|- references.d.ts //爲編輯器提供TypeScript的智能提示
|- node_modules //依賴的庫文件
|- platforms //由NativeScript自動生成和維護
|- package.json //描述應用程序的特徵和依賴項
複製代碼
// package.json
{
"description": "NativeScript Application", //提供應用程序、功能和用途的簡要說明
"license": "SEE LICENSE IN <your-license-filename>", //將協做開發人員指向您的許可文件,以描述其餘人必須對您的應用程序代碼做出貢獻、修改、更改和從新分發哪些權限(可選)
"readme": "NativeScript Application", //指向應用程序的README文件
"repository": "<fill-your-repository-here>", //應用程序公共或私有代碼存儲庫的位置(可選)
"nativescript": { //一個特定於nativescript的部分,帶有應用程序的標識符,Android和iOS平臺使用它唯一地標識應用程序
"id": "org.nativescript.myapp"
},
"dependencies": { //npm使用的外部庫和應用程序所依賴的庫版本的列表
"nativescript-theme-core": "~1.0.2",
"tns-core-modules": "3.1.0"
}
}
複製代碼
|- app
|- views
|- home
|- home.css
|- home.xml
|- home.js
|- about
|- about.css
|- about.xml
|- about.js
複製代碼
require("./bundle-config");
var application = require("application");
application.start({ moduleName: "views/home/home" }); //將moduleName的鍵值修改爲home頁面的路徑
複製代碼
<Page> //頁面中全部其餘元素的容器,相似於網頁開發裏面的body標籤
<StackLayout> //佈局元素,相似於網頁開發裏面的div標籤
<Label text="Welcome to the Tekmo App!" /> //在屏幕上顯示文本
</StackLayout>
</Page>
複製代碼
<Page>
<StackLayout>
<Label textWrap="true" text="Small company that wants to bring you the best in retro gaming!" /> //textWrap爲true時會自動換行
<Label text="Come visit us in Louisville, KY" />
</StackLayout>
</Page>
複製代碼
<Page>
<StackLayout>
<Label text="Welcome to the Tekmo App!" />
<Button text="About" tap="onTap" /> //tap屬性告訴NativeScript在單擊按鈕時調用onTap這個JavaScript函數
</StackLayout>
</Page>
複製代碼
var frameModule = require("ui/frame"); //獲取NativeScript框架中導航模塊的引用
function onTap() {
frameModule.topmost().navigate("views/about/about "); //使用frame模塊導航到about頁面
}
exports.onTap = onTap; //必須導出該函數,以便NativeScript運行時能夠從UI訪問它
複製代碼
以下表所示是各個平臺支持的過渡動畫node
接下來讓咱們看一下如何將這些過渡動畫添加到導航跳轉,在home.js中寫入以下代碼var frames = require("ui/frame");
function onTap() {
var navigationEntry = {
moduleName: "views/about/about",
transition: {
name: "slideBottom" //將想要應用的過渡動畫寫在這裏
}
};
frames.topmost().navigate(navigationEntry);
}
exports.onTap = onTap;
複製代碼
參考文檔進行學習android
參考文檔進行學習webpack
<Page loaded="onLoaded">
<StackLayout>
<Label text="{{ Name }}" /> //在{{}}內寫入須要綁定的變量
</StackLayout>
</Page>
複製代碼
var observableModule = require("data/observable");
var viewModule = require ("ui/core/view");
exports.onLoaded = function(args){
var page = args.object;
var pet = new observableModule.Observable(); //pet對象是一個可觀察的對象,它將綁定到頁面上的全部元素
page.bindingContext = pet; //將pet設置爲頁面的綁定上下文,將其設置爲用於綁定的頁面級可觀察對象
pet.set("Name", "Riven");
//也能夠寫成下面的形式
//var pet = new observable.fromObject({
// Name: "Riven"
//});
//page.bindingContext = pet;
}
複製代碼
<Page loaded="onLoaded">
<StackLayout>
<ListView items="{{ pages }}" itemTap="onItemTap"> //pages是一個可觀察數組
<ListView.itemTemplate> //pages中的每一項會被渲染一次
<StackLayout>
<Label text="{{ title, title + ' Scrapbook Page' }}" /> //pages每一項上的title
</StackLayout>
</ListView.itemTemplate>
</ListView>
</StackLayout>
</Page>
複製代碼
var observable = require("data/observable");
var observableArray = require("data/observable-array");
exports.onLoaded = function(args) {
var page = args.object;
var filledPage = new observable.Observable({
title: "Riven's Page"
});
var home = new observable.Observable({
pages: new observableArray.ObservableArray(filledPage) //生成可觀察對象數組
});
page.bindingContext = home;
};
複製代碼
能夠將數據綁定的內容封裝成單獨的pageName-view-model.js文件,方便多個頁面共用一個view model.git
var fileSystemModule = require("file-system"); //要使用文件系統模塊,須要導入它
exports.onLoaded = function(){
var fileName = "myFile.json";
var file = fileSystemModule.knownFolders.documents().getFile(fileName); //使用documents文件夾存儲應用程序須要的離線文件
var data = {name: "Brosteins", type: "filesystemexample"};
var jsonDataToWrite = JSON.stringify(data);
file.writeText(jsonDataToWrite); //將數據寫入文件系統
console.log("Wrote to the file: " + jsonDataToWrite);
var jsonDataRead = file.readTextSync(); //使用對文件的引用來讀取數據。數據能夠同步讀取,也能夠異步讀取
console.log("Read from the file: " + jsonDataRead);
file.remove(); //刪除該文件
};
複製代碼
安裝相機的插件:npm install nativescript-camera --save
web
var camera = require("nativescript-camera");
var image = require("image-source");
exports.onAddImageTap = function (args) {
var page = args.object;
var scrapbookPage = page.bindingContext;
camera.requestPermissions(); //要使用照相機須要得到許可
camera
.takePicture() //返回一個promise
.then(function (picture) { //當promise解析後,調用then()函數,傳遞圖片
image.fromAsset(picture).then(function (imageSource) {
scrapbookPage.set("image", imageSource); //建立要綁定到視圖的圖像源對象
});
});
}
複製代碼
若是保存圖片,須要先用 image.toBase64String("png") 將圖片的二進制數據轉換成base64字符串而後再保存起來。npm
安裝定位的插件:tns plugin add nativescript-geolocation
var camera = require("nativescript-camera");
var image = require("image-source");
var geolocation = require("nativescript-geolocation");
exports.onAddImageTap = function (args) {
var page = args.object;
var scrapbookPage = page.bindingContext;
if (!geolocation.isEnabled()) { //在使用位置服務以前,應該檢查是否啓用了它,並請求啓用它
geolocation.enableLocationRequest();
}
camera
.takePicture({ width: 100, height: 100, keepAspectRatio: true })
.then(function (picture) {
image.fromAsset(picture).then(function (imageSource) {
scrapbookPage.set("image", imageSource);
});
geolocation.getCurrentLocation().then(function (location) { //獲取位置數據會自動提示用戶請求權限
scrapbookPage.set("lat", location.latitude); //返回的位置的緯度值
scrapbookPage.set("long", location.longitude); //返回的位置的經度值
});
});
};
複製代碼
參考文檔進行學習
<Page backgroundColor="green" loaded="onLoaded">
<StackLayout backgroundColor="lightGreen">
<Button text="BirthDate" tap="onBirthDateTap"/>
</StackLayout>
</Page>
複製代碼
var page;
exports.onLoaded = function(args) {
page = args.object;
var scrapbookPage = page.navigationContext.model;
page.bindingContext = scrapbookPage;
};
exports.onBirthDateTap = function(args) {
var modalPageModule = "views/selectDate-page";
var context = { birthDate: page.bindingContext.birthDate };
var fullscreen = true;
page.showModal(
modalPageModule,
context,
function closeCallback(birthDate) { //關閉modal時的回調函數,能夠將modal頁面的數據傳遞回來
page.bindingContext.set("birthDate", birthDate);
},
fullscreen
);
};
複製代碼
<Page shownModally="onShownModally" loaded="onLoaded">
<StackLayout>
<DatePicker date="{{ date }}" />
<Button class="btn btn-primary btn-rounded-sm btn-active" text="Done" tap="onDoneTap" />
</StackLayout>
</Page>
複製代碼
var observableModule = require("data/observable");
var model;
var closeCallback;
exports.onLoaded = function(args) {
var page = args.object;
model = new observableModule.fromObject({
date: new Date(Date.now())
});
page.bindingContext = model;
};
exports.onShownModally = function(args) {
closeCallback = args.closeCallback;
};
exports.onDoneTap = function(args) { closeCallback(model.date); };
複製代碼
能夠建立 page-name.land.minWH600.xml
,page-name.land.minWH600.js
,page-name.land.minWH600.css
文件單獨寫平板端的頁面。
Android的app圖標放在 App_Resources目錄下的drawable-*的各個文件夾中,也就是不一樣分辨率的設備用相應的圖標
不經過文件夾對應的設備的分辨率以下表所示: 因此修改Android的app圖標時,能夠先在這個 網站生成須要的圖標再放入對應文件夾。 在App_Resources/ AndroidManifest.xml
文件中有關於app的各項設置
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/icon" //在這裏修改app的圖標 android:label="@string/app_name" //在string.xml裏配置app_name android:theme="@style/AppTheme" >
<activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" //在string.xml裏配置使用時app的名字 android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tns.ErrorReportActivity"/>
</application>
複製代碼
在 App_Resources\iOS\Assets.xcassets\AppIcon.appiconset
文件下放入用入在這個網站下生成的iOS須要的適配各類設備的圖標
在 App_Resources/Android/values/strings.xml
裏面修改app的名字
<resources>
<string name="app_name">Pet Scrapbook</string> //在這裏改應用程序的名稱
<string name="title_activity_kimera">Pet Scrapbook</string> //使用時app的名字
</resources>
複製代碼
在App_Resources/iOS/Info.plist
裏面修改app的名字
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string> //在這裏修更名字,能夠把名字直接寫在<string>標籤裏
複製代碼
在App_Resources/ AndroidManifest.xml
裏配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="__PACKAGE__" android:versionCode="1" //用戶看不到的內部版本號 android:versionName="1.0"> //用戶在谷歌商店能夠看到的版本號
複製代碼
在App_Resources/iOS/Info.plist
裏面修改app的版本號
<key>CFBundleVersion</key>
<string>1.0.0</string> //版本號
複製代碼
<key>CFBundleShortVersionString</key>
<string>1.0.0</string> //構建號
複製代碼
在App_Resources/ AndroidManifest.xml
裏配置
<supports-screens android:smallScreens="true" //支持約2-3英寸的屏幕 android:normalScreens="true" //支持約2-5英寸的屏幕 android:largeScreens="true" //支持約4-7英寸的屏幕 android:xlargeScreens="true"/> //支持約7+英寸的屏幕
複製代碼
Android屏幕大小和相應的屏幕分辨率DPIs以下表所示
在App_Resources/iOS/Info.plist
裏適配各類設備
<key>UISupportedInterfaceOrientations</key> //適配iPhones
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key> //適配iPads
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
複製代碼
drawable-nodpi
目錄下的splash_screen.xml
配置了app的啓動頁面
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:gravity="fill">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background" /> //啓動屏幕的背景圖
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/logo" /> //啓動屏幕中心的logo圖片
</item>
</layer-list>
複製代碼
啓動屏幕的背景圖和中心的logo圖配置的方法和app的圖標是相同的
App_Resources\iOS\Assets.xcassets\LaunchScreen.AspectFill.imageset
裏放啓動屏幕的背景圖App_Resources\iOS\Assets.xcassets\LaunchScreen.Center.imageset
裏放啓動屏幕中心的logo圖片 能夠在這個網站生成適配各類設備的圖片