Интеграция мобильных веб-редакторов Р7 на платформе IOS

Чтобы получить доступ к функциям редактора в своем мобильном приложении, интегрируйте его с редакторами Р7 через компонент WebView — системный компонент, отвечающий за открытие веб-страниц в приложениях. После этого пользователи смогут просматривать, создавать и редактировать текстовые документы, электронные таблицы и презентации, заполнять формы и читать PDF-файлы прямо на своих устройствах iOS или Android.

Интеграция на базе тестового образца

В этом примере показано, как интегрировать мобильные веб-редакторы Р7 с тестом или образцом DMS.

Открытие редакторов Р7

  1. Загрузите и установите Р7 Document Server.
  2. Откройте проект EditorWebViewDemo.xcodeproj с помощью Xcode.
  3. Для отображения главной страницы вашей DMS укажите адрес веб-интерфейса Сервера документов в значении свойства DocumentServerURL в файле Info.plist:
    <dict>
        ...
        <key>DocumentServerURL</key>
        <string>https://documentserver/</string>
    </dict>
    

    где documentserver — это имя сервера, на котором установлен Сервер документов Р7.

    Если указан DocumentServerURL, загружается главная страница DMS. В противном случае возникает ошибка:

    private func load(){
        if documentServerUrlString.isEmpty {
            showAlert(title: "Error", message: "You must specify the document server address, the \"DocumentServerURL\" value in the Info.plist file.")
            return
        }
    
        guard let url = URL(string: documentServerUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "") else {
            return
        }
    
        webView.load(URLRequest(url: url))
    }
    

    DocumentServerURL не указан

    Указан DocumentServerURL

  4. Используйте контроллер MainFragment.kt, чтобы корректно открывать редакторы на устройствах Android. В этом контроллере определите функцию для открытия документа через компонент WebView. Запросите URL-адрес и проверьте, содержит ли он строку «редактор», указывающую, что документ будет открыт:
    private var openDocumentMarker = "/editor?"
    private var additionalQueryParameters = ["type": "mobile"]
    
    func webView(_ webView: WKWebView,
        decidePolicyFor navigationAction:
        WKNavigationAction,
        decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
    {
        guard let urlString = navigationAction.request.url?.absoluteString else {
            decisionHandler(.cancel)
            return
        }
    
        if urlString.contains(openDocumentMarker),
           let redirectUrl = navigationAction.request.url?.appendingQueryParameters(additionalQueryParameters)
        {
            decisionHandler(.cancel)
            navigator.navigate(to: .documentServerEditor(url: redirectUrl))
        } else {
            reloadItem.isEnabled = true
            backItem.isEnabled = webView.canGoBack
            forwardItem.isEnabled = webView.canGoForward
    
            title = navigationAction.request.url?.host ?? ""
    
            decisionHandler(.allow)
        }
    
    }
    
  5. В контроллере DocumentServerViewController создайте действия навигации, доступные на главной странице DMS. Например, в нашем тестовом образце они указаны с помощью таких элементов интерфейса, как кнопки «Обновить», «Назад» и «Вперед».
    Для удобства взаимодействия с редактором определите компоненты интерфейса Activity Indicator и Progress View.

    Индикатор активности

    Просмотр прогресса

    Кнопки

  6. Чтобы начать работу с документами, откройте редактор Р7 на мобильном устройстве через компонент WKWebView.
    Для этого настройте WKWebView и макет в контроллере  DocumentServerEditorViewController следующим образом:

    private func configureView(){
        let preferences = WKPreferences()
        let configuration = WKWebViewConfiguration()
        preferences.javaScriptEnabled = true
        configuration.preferences = preferences
    
        webView = WKWebView(frame: .zero, configuration: configuration)
    
        view.addSubview(webView)
        webView.translatesAutoresizingMaskIntoConstraints = false
    
        webView.navigationDelegate = self
        webView.uiDelegate = self
    
        if let webViewSuperview = webView.superview {
            webView.topAnchor.constraint(equalTo: webViewSuperview.topAnchor).isActive = true
            webView.leadingAnchor.constraint(equalTo: webViewSuperview.leadingAnchor).isActive = true
            webView.bottomAnchor.constraint(equalTo: webViewSuperview.bottomAnchor).isActive = true
            webView.trailingAnchor.constraint(equalTo: webViewSuperview.trailingAnchor).isActive = true
        }
    ...
    }
    

8. На панели инструментов Xcode выберите схему сборки и устройство, на котором будет выполняться приложение.
После этого выберите «Продукт» -> «Выполнить» или нажмите кнопку «Выполнить» на панели инструментов проекта, чтобы создать и запустить код.
9. На главном экране приложения выберите вариант «Использование DocumentServer», чтобы продемонстрировать пример интеграции мобильных веб-редакторов Р7 с тестовым образцом Р7 или образцом DMS.

Закрытие редакторов Р7

Используйте контроллер DocumentServerEditorViewController для выхода из редактора.
Например, в текущих тестовых примерах кнопка «Назад» создана для перехода к предыдущему экрану:

private let goBackUrl = Bundle.main.object(forInfoDictionaryKey: "DocumentServerURL") as? String ?? ""

func webView(_ webView: WKWebView,
    decidePolicyFor navigationAction: WKNavigationAction,
    decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
{
    guard let urlString = navigationAction.request.url?.absoluteString else {
        decisionHandler(.cancel)
        return
    }
        
    if urlString == goBackUrl {
        decisionHandler(.cancel)
        navigationController?.popViewController(animated: true)
    } else {
        decisionHandler(.allow)
    }
}

Кнопка выхода из редактора

Интеграция на основе Р7 Document Server API

В этом примере показано, как открыть редакторы Р7 через WKWebView, используя конфигурацию редактора, описанную в документации API и примерах конфигурации.

Открытие редакторов Р7

  1. Загрузите и установите документ сервер.
  2. Откройте проект EditorWebViewDemo.xcodeproj с помощью Xcode, чтобы изменить фрагменты кода этого примера, чтобы ваша DMS работала правильно.
  3. Создайте пустой html-файл.
  4. Добавьте элемент div, как показано ниже:
<div id="placeholder"></div>

5. Укажите ссылку на Сервер документов Р7 с API JavaScript, который будет использоваться для вашего сайта:

<script type="text/javascript" src="https://documentserver/web-apps/apps/api/documents/api.js"></script>

где documentserver — это имя сервера, на котором установлен Сервер документов Р7.

6. Добавьте скрипт, инициализирующий редактор документов для элемента div с конфигурацией документа, который вы хотите открыть:

window.docEditor = new DocsAPI.DocEditor("placeholder",
    {
        {external_config},
        "type": "mobile",
        "events": {
            "onAppReady": onAppReady,
            "onDocumentReady": onDocumentReady,
            "onDownloadAs": onDownloadAs,
            "onError": onError,
            "onInfo": onInfo,
            "onRequestClose": onRequestClose,
            "onRequestInsertImage": onRequestInsertImage,
            "onRequestUsers": onRequestUsers,
            "onWarning": onWarning,
        }
    });

7.  Чтобы начать работу с документами, откройте редактор Р7 на мобильном устройстве через компонент WKWebView. Для этого укажите контроллер EditorViewController. Запросите URL-адрес файла editor.html, получите его содержимое и замените параметр «{external_config}» конфигурацией из файла Samples.plist, где все примеры конфигураций распределены по категориям в соответствии с API documentation Try page:

private func load(){
    guard let url = Bundle.main.url(forResource: "editor", withExtension: "html") else {
        return
    }

    var html = ""

    do {
        html = try String(contentsOf: url)
    } catch{
        print(error)
    }

    html = html.replacingOccurrences(of: "{external_config}", with: config ?? "")
    webView.loadHTMLString(html, baseURL: nil)
}

Образцы редактора Р7

8.  На панели инструментов Xcode выберите схему сборки и устройство, на котором будет запускаться приложение. После этого выберите «Продукт» -> «Выполнить» или нажмите кнопку «Выполнить» на панели инструментов проекта, чтобы создать и запустить код.
9. На главном экране приложения выберите параметр «Использование конфигурации API», чтобы продемонстрировать, как открывать мобильные веб-редакторы Р7, используя конфигурацию редактора, описанную в документации API и примерах конфигурации.
10. На следующей странице выберите один из примеров конфигурации, чтобы открыть полученный HTML-код в компоненте WKWebView.

Работа с документами

Для работы с документами (открывать, скачивать, вставлять изображения, упоминать других пользователей и т. д.) используйте документацию API с ее событиями и методами:

  1.  Чтобы отслеживать события и вызывать соответствующие методы, обрабатывайте события редакторов Р7 в нативном коде с помощью контроллера EditorEventsHandler, а затем делегируйте их в EditorViewController:
    var delegate: EditorEventsDelegate?
    
    convenience init(configuration: WKWebViewConfiguration){
        self.init()
       
        configuration.userContentController.add(self, name: EditorEvent.onDownloadAs.rawValue)
        ....
    }
    
    extension EditorEventsHandler: WKScriptMessageHandler {
        func userContentController(_ userContentController: WKUserContentController,
            didReceive message: WKScriptMessage){
            let event = EditorEvent(rawValue: message.name)
    
            switch event {
            case .onDownloadAs:
                guard
                    let json = message.body as? [String: Any],
                    let fileType = json["fileType"] as? String,
                    let url = json["url"] as? String
                else { return }
    
                delegate?.onDownloadAs(fileType: fileType, url: url)
            ...
            }
        }
    }
    

    В качестве примера рассмотрим событие onDownloadAs. Зарегистрируйте объект в качестве обработчика определенного сообщения, вызвав configuration.userContentController.add(self, name: messageName) во время настройки WKWebView.
    Получите параметры события (тип файла и URL-адрес) и делегируйте обработку события EditorViewController:

    func onDownloadAs(fileType: String, url: String){
        print("⚡ Р7 Document Editor create file: \(url)")
    }
    
  2. Определите функцию callMethod для вызова методов API из нативного кода. В качестве аргументов он может принимать строковые, логические или объектные значения. Эта функция добавляет имя метода и его аргументы в строку с кодом JavaScript, а затем оценивает JavaScript в компоненте WKWebView с помощью метода evaluateJavaScript: 
    private func callMethod(function: String, arg: Bool){
        let javascript = "window.docEditor.\(function)(\(arg))"
        webView.evaluateJavaScript(javascript, completionHandler: nil)
    }
    
    private func callMethod(function: String, arg: String){
        let javascript = "window.docEditor.\(function)(\"\(arg)\")"
        webView.evaluateJavaScript(javascript, completionHandler: nil)
    }
    
    private func callMethod(function: String, arg: [String: Any]){
        guard
            let json = try? JSONSerialization.data(withJSONObject: arg, options: []),
            let jsonString = String(data: json, encoding: .utf8)
        else {
            return
        }
    
        let javascript = "window.docEditor.\(function)(\(jsonString))"
        webView.evaluateJavaScript(javascript, completionHandler: nil)
    }
    

     

  3. Чтобы отобразить результат загрузки и печати документа, используйте контроллер PreviewController. Этот контроллер основан на QLPreviewController. Загрузите документ по его URL-адресу и установите для свойств dataSource и делегировать значение QLPreviewController:
    func present(url: URL, in parent: UIViewController, complation: @escaping (() -> Void)) {
        download(url: url) { fileUrl in
            DispatchQueue.main.async {
                guard let fileUrl = fileUrl else {
                    complation()
                    return
                }
    
                self.fileUrl = fileUrl
    
                let quickLookController = QLPreviewController()
                quickLookController.dataSource = self
                quickLookController.delegate = self
    
                if QLPreviewController.canPreview(fileUrl as QLPreviewItem) {
                    quickLookController.currentPreviewItemIndex = 0
                    parent.present(quickLookController, animated: true, completion: nil)
                }
                complation()
            }
        }
    }