深入淺出 Fuse

jopen 8年前發布 | 13K 次閱讀 iOS開發 前端技術 JavaScript

在上次Fuse 15 分鐘入門教程 之后,用 Fuse 開發的第一個 AppProducter 也提交到了 App Store

代碼已經開源在了 Github 這篇文章將用來總結一些 Fuse 開發中的 “深坑” 和經驗。

引入 Javascript 庫

Fuse 的邏輯層都是由 Javascript 來處理,那么利用一些好用的庫會使得我們的開發更為有效,以 Moment.js 為例,這是前端常用的一個時間解析庫。

第一步就是到 http://momentjs.com 下載最新版本的庫,把 moment with locales 這庫存儲到項目目錄里,例如我存儲在了 assets/js 目錄下,那么在 MainView.ux 里,既可以這樣載入這個模塊

<JavaScript File="assets/js/moment.min.js" ux:Global="Moment"/>  

如果要使用這庫,就可以在 Javascript 文件里這樣 require 它,require 里的字符串要和我們 ux:Global 里寫的一樣

var Moment = require('Moment');  

接下來你就可以直接用 Moment 來解析時間了。

讀取本地文件

在 Producter App 里我用到了 Webview 來結合 JSON 和本地的 HTML 模版顯示文章,Fuse 的 Javascript 并沒有接口可以讀取本地文件,所以需要利用 Uno 來實現這個功能。

首先確保你的 .unoproj 里的 Includes 里有打包 *.html

  "Includes": [
    "*",
    "*.html"
  ]

隨后將下面這段代碼保存為 TextFile.uno

using Uno;  
using Uno.Collections;  
using Fuse;  
using Uno.UX;  
using Fuse.Scripting;  
using Fuse.Reactive;

public class TextFile: NativeModule  
{
    readonly FileSource _file;

    [UXConstructor]
    public TextFile([UXParameter("File")] FileSource file)
    {
         AddMember(new NativeFunction("readSync", (NativeCallback)readSync));
        _file = file;
    }

    object readSync(Context c, object[] args)
    {
        return _file.ReadAllText();
    }
}

在開始我們用 using 引用了一些我們會用到的庫,這些被引用的庫要確保存在于 .unoproj 里,你可以參考 Producter 的配置文件

  "Packages": [
        "Fuse.PushNotifications",
        "Fuse.Animations",
        "Fuse.BasicTheme",
        "Fuse.Themes",
        "Fuse.Controls",
        "Fuse.Designer",
        "Fuse.Drawing",
        "Fuse.Drawing.Primitives",
        "Fuse.Effects",
        "Fuse.Elements",
        "Fuse.Entities",
        "Fuse.Gestures",
        "Fuse.Navigation",
        "Fuse.Shapes",
        "Fuse.Triggers",
        "Fuse.Reactive",
        "Fuse.Android",
        "Fuse.Desktop",
        "Fuse.iOS",
        "FuseCore",
        "Fuse.Launcher",
        "Uno.Collections",
        "Uno.Geometry",
        "Fuse.Scripting",
        "Experimental.iOS",
        "ObjC"
  ]

TextFile 這個類后面還有一個 NativeModule 繼承,通過這個繼承就使得我們這個類可以通過 <TextFile /> 的形式放在 Mainview.ux 里,所有自定義的類都需要用這樣的方式加載到我們的 Fuse App 里。

更詳細的 NativeModule 使用細節可以參考官方的 Guide Working with Uno Code

UXConstructor 字段的修飾讓 <TextFile /> 在創建這個類的時候知道 <TextFile File="xxxxx"/> 對應 [UXParameter("File")] FileSource file 傳遞構造參數給這個類的構造方法。

在 readSync 方法里,通過 ReadAllText() 讀取了路徑文本,那么接下來還有一件事情就是要把這個方法暴露給 Javascript。

通過 AddMember(new NativeFunction("readSync", (NativeCallback)readSync)); 我們可以讓 Uno 完成方法到 Javascript 的橋接。

完成這兩步之后,在 Mainview.ux 加入文件的引用

<TextFile File="videoHTMLTemplate.html" ux:Global="videoHTMLTemplate" />  

接下來就可以在 Javascript 里使用這個文件了

var videoHTMLTemplate = require("videoHTMLTemplate");  
// Read Templates
var videoHTMLTemplateString = videoHTMLTemplate.readSync();  

最后 Webview 通過 Source 屬性將我們自己生成好的 HTML 填充進去, presentedArticleHTML 綁定到了我們自己生成的 HTML 數據上。

<WebView Source="{presentedArticleHTML}" >  
</WebView>  

調用 iOS API

在后續的版本會舍棄現在的調用方法,引入 Foreigon Code 的模式,不過官方說還有幾周的時間,所以這個即將過時的方法就先帖出來吧。

這種模式依賴于 Uno,Uno 一面把接口暴露給 Javascript,一面去調用 iOS 的接口。

具體的例子可以參考 Producter 的 FuseStoreKit.uno 這個文件,里面的用法已經相當深入,觸及了 API 調用的瓶頸,這也正是為什么 Fuse 接下來要棄用 Uno 橋接的原因。

如果需要引用某些 iOS 的庫,確保 .unoproj 已經引入了 Objc 和 Experimental.iOS 這兩個庫,不確定話可以直接照搬 Producter 的配置文件。

例如我們需要引用 iOS 的 StoreKit 庫,那么可以用下面的語句

using global::iOS.StoreKit;  

因為我們的 NativeModule 需要同時存在于 iOS 和 Android,所以 FuseStoreKit 其實是我們實際接口操作類的上一層代理,避免直接調用發生悲劇。

public class FuseStoreKit : NativeModule  
{

  extern(iOS)
  StoreKit storeKit = new StoreKit();

  extern(iOS)
  Storage storage = new Storage();

  extern(iOS)
  CloudKit cloudKit = new CloudKit();
}

extern 表示僅當是 iOS 平臺的時候才會創建下面的屬性。

而具體的方法在執行的時候,也用了 defined 來確保只有在正確的平臺上才會執行,如果不是這個平臺,Javascript 在調用的時候,就會 null。

  object MakeSubscribe(Context c, object[] args) {
    if defined (iOS) {
      Subscribe();
    }
    return null;
   }

具體創建 iOS 類的時候,在 Uno 里寫起來沒有 iOS 那么得心應手,init 方法和類方法都有著不同的調用規則,例如創建 NSUserDefaults 的時候,要這樣去寫

NSUserDefaults userDefaults = new NSUserDefaults(NSUserDefaults._standardUserDefaults());  

NSUserDefaults 的 standardUserDefaults 是一個類方法,因此要加下劃線,然后通過 new NSUserDefaults() 來包住這個方法去創建。

如果是 init 方法,那么使用起來就更麻煩一些,先初始化,然后再 init。

NSString begin = new NSString();  
begin.initWithString("producter_month_subscribe");  

奇技淫巧參考 FuseStoreKit.uno 中我注釋掉的代碼。

Delegate

有些需要注意的是, .delegate = this 這種直接的屬性賦值通常是不能工作的,需要使用 request.setDelegate(this); 這種方法。

其次是 Objective C 的方法如果有多個參數一般是成段隔開的,在 Uno 里要合成一段然后再在括號里分別傳入參數,例如以下這段

- (void)paymentQueue:(SKPaymentQueue *)queue
restoreCompletedTransactionsFailedWithError:(NSError *)error  

那么在 Uno 里就要這樣寫

public void paymentQueueRestoreCompletedTransactionsFailedWithError (SKPaymentQueue queue, NSError error)  
{
    // Restore failed somewhere...
}

目前 Objc 的閉包回調函數在 Uno 里還沒實現,有個叫 UXL 的可以做,但是…… 我們還是等 Foreigon Code 吧。

來自: http://tips.producter.io/shen-ru-qian-chu-fuse/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!