PC SOFT

PROFESSIONAL NEWSGROUPS
WINDEVWEBDEV and WINDEV Mobile

Home → WINDEV 25 → ScreenShot iOS
ScreenShot iOS
Started by mateusdev, Jul., 17 2025 4:41 PM - 4 replies
Registered member
2 messages
Posted on July, 17 2025 - 4:41 PM
Bom dia, boa tarde ou boa noite, pessoal!

Estou com uma demanda de um cliente que deseja bloquear a captura de tela do aplicativo. Sei que no Android isso é possível utilizando uma função nativa da ferramenta (MyWindow.ScreenshotAllowed = False), o que resolve o problema por lá.

Porém, no iOS a Apple não permite o bloqueio direto de capturas de tela (print screen). Diante disso, gostaria de saber se existe alguma forma de detectar quando o usuário tira um print no iOS, mesmo que indiretamente — por exemplo, para que eu possa aplicar um efeito visual, como blur ou escurecimento temporário da tela após a detecção.

Se alguém tiver alguma dica ou já implementou algo semelhante, agradeço pela ajuda!
Registered member
4,520 messages
Posted on July, 17 2025 - 4:50 PM
Bom dia

Coloca um botão na posição x -2000

Em description do botão

Hot key a combinação de teclas que faz a captura

Em Code

RETURN

1 linha de código

Simples assim!!!!

O botão está quente com o comando e o que vai fazer é nao Deixar acontecer !

Pog do Boller

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Registered member
4,520 messages
Posted on July, 17 2025 - 6:32 PM
Na windows do mobile
Em Details
Desmarcar
Allow window screenshot


_José Willem_

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Registered member
4,520 messages
Posted on July, 17 2025 - 7:22 PM
No iOS, não é possível bloquear completamente o print screen (screenshot) devido às políticas de segurança da Apple, mas você pode implementar algumas medidas de proteção:

## 1. Detectar quando um screenshot foi tirado

```swift
import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Observador para detectar screenshots
NotificationCenter.default.addObserver(
self,
selector: #selector(screenshotTaken),
name: UIApplication.userDidTakeScreenshotNotification,
object: nil
)
}

@objc func screenshotTaken() {
// Ação quando screenshot é detectado
showScreenshotAlert()
// Você pode registrar o evento, enviar para analytics, etc.
}

func showScreenshotAlert() {
let alert = UIAlertController(
title: "Screenshot Detectado",
message: "Por favor, não tire screenshots deste conteúdo sensível.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}
```

## 2. Ocultar conteúdo quando o app vai para background

```swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?
private var overlayView: UIView?

func sceneWillResignActive(_ scene: UIScene) {
// Adiciona uma overlay quando o app vai para background
addSecurityOverlay()
}

func sceneDidBecomeActive(_ scene: UIScene) {
// Remove a overlay quando o app volta
removeSecurityOverlay()
}

private func addSecurityOverlay() {
guard let window = window else { return }

overlayView = UIView(frame: window.bounds)
overlayView?.backgroundColor = .white

let label = UILabel()
label.text = "Conteúdo Protegido"
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 24, weight: .bold)
label.translatesAutoresizingMaskIntoConstraints = false

overlayView?.addSubview(label)
window.addSubview(overlayView!)

NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: overlayView!.centerXAnchor),
label.centerYAnchor.constraint(equalTo: overlayView!.centerYAnchor)
])
}

private func removeSecurityOverlay() {
overlayView?.removeFromSuperview()
overlayView = nil
}
}
```

## 3. Proteger views específicas contra captura de tela

```swift
extension UIView {
func makeSecureAgainstScreenshots() {
// Cria uma subview que não aparece em screenshots
let field = UITextField()
field.isSecureTextEntry = true
field.isUserInteractionEnabled = false
field.backgroundColor = .clear
field.translatesAutoresizingMaskIntoConstraints = false

self.addSubview(field)
field.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
field.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
field.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
field.heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true

// Move o conteúdo para dentro do campo seguro
field.layer.superlayer?.addSublayer(self.layer)
}
}
```

## 4. Implementação mais robusta com ViewController personalizado

```swift
class SecureViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
setupSecurityMeasures()
}

private func setupSecurityMeasures() {
// Detectar screenshots
NotificationCenter.default.addObserver(
self,
selector: #selector(handleScreenshot),
name: UIApplication.userDidTakeScreenshotNotification,
object: nil
)

// Detectar gravação de tela
NotificationCenter.default.addObserver(
self,
selector: #selector(handleScreenRecording),
name: UIScreen.capturedDidChangeNotification,
object: nil
)
}

@objc private func handleScreenshot() {
// Log do evento
print("Screenshot detectado em: \(Date())")

// Implementar sua lógica de segurança
showSecurityWarning()
}

@objc private func handleScreenRecording() {
if UIScreen.main.isCaptured {
// Tela está sendo gravada
showRecordingWarning()
// Você pode ocultar conteúdo sensível aqui
hidesSensitiveContent(true)
} else {
hidesSensitiveContent(false)
}
}

private func showSecurityWarning() {
// Implementar alerta ou ação de segurança
}

private func showRecordingWarning() {
// Avisar sobre gravação de tela
}

private func hidesSensitiveContent(_ hide: Bool) {
// Ocultar/mostrar conteúdo sensível
view.subviews.forEach { $0.isHidden = hide }
}

deinit {
NotificationCenter.default.removeObserver(self)
}
}
```

## Limitações importantes:

- **Não é possível bloquear completamente** screenshots no iOS por design da Apple
- O iOS permite que usuários façam screenshots para acessibilidade
- Apps não podem interferir nas funcionalidades básicas do sistema
- Estas são medidas de **detecção e dissuasão**, não bloqueio absoluto

## Alternativas complementares:

1. **Watermarks** em conteúdo sensível
1. **Expiração** de conteúdo após tempo determinado
1. **Autenticação** adicional para acessar dados sensíveis
1. **Logs de auditoria** quando screenshots são detectados

Essas implementações ajudam a proteger conteúdo sensível, mesmo que não possam bloquear completamente os screenshots no iOS.

Teste com procedimento swift não WL. No canto superior mude de WL para Swift na code da procedure, Teste em linguagem nativa esses códigos acima.

Bons estudos

Forte abraço

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Registered member
4,520 messages
Posted on July, 17 2025 - 7:42 PM
O Windev Mobile permite integrar código Swift nativo em projetos iOS através de várias técnicas. Aqui estão as principais abordagens:

## 1. Chamadas de Funções Swift via iOSAppelFonctionSwift()

```windev
// No Windev Mobile - chamando função Swift
PROCÉDURE ChamarFuncaoSwift()

// Chamada simples
sResultado é string = iOSAppelFonctionSwift("MinhaFuncaoSwift", "parametro1", 123)

// Chamada com múltiplos parâmetros
nValor é numeric = iOSAppelFonctionSwift("CalcularValor", 10, 20, 30)

// Retorno de objeto JSON
sJSON é string = iOSAppelFonctionSwift("ObterDadosComplexos", "chave")
stDados é Variant = JSONVersStructure(sJSON)
```

```swift
// Arquivo Swift nativo (ex: Funcoes.swift)
@objc public class FuncoesNativas: NSObject {

@objc public static func MinhaFuncaoSwift(_ param1: String, _ param2: Int) -> String {
return "Resultado: \(param1) - \(param2)"
}

@objc public static func CalcularValor(_ a: Int, _ b: Int, _ c: Int) -> Int {
return a + b + c
}

@objc public static func ObterDadosComplexos(_ chave: String) -> String {
let dados = [
"chave": chave,
"timestamp": Date().timeIntervalSince1970,
"status": "sucesso"
]

do {
let jsonData = try JSONSerialization.data(withJSONObject: dados)
return String(data: jsonData, encoding: .utf8) ?? "{}"
} catch {
return "{\"erro\": \"Falha na serialização\"}"
}
}
}
```

## 2. Integração com Frameworks iOS Nativos

```swift
// Framework para Camera/Fotos
@objc public class CameraManager: NSObject {

@objc public static func abrirCamera() -> String {
DispatchQueue.main.async {
let picker = UIImagePickerController()
picker.sourceType = .camera

if let rootVC = UIApplication.shared.windows.first?.rootViewController {
rootVC.present(picker, animated: true)
}
}
return "camera_aberta"
}

@objc public static func verificarPermissaoCamera() -> Bool {
return AVCaptureDevice.authorizationStatus(for: .video) == .authorized
}
}

// Framework para Localização
@objc public class LocationManager: NSObject, CLLocationManagerDelegate {

private let locationManager = CLLocationManager()
private var callback: String = ""

@objc public static func obterLocalizacao(_ callbackWD: String) -> String {
let manager = LocationManager()
manager.callback = callbackWD
manager.startLocationUpdates()
return "solicitacao_enviada"
}

private func startLocationUpdates() {
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }

let dados = [
"latitude": location.coordinate.latitude,
"longitude": location.coordinate.longitude,
"precisao": location.horizontalAccuracy
]

// Chama procedimento WinDev
if let jsonData = try? JSONSerialization.data(withJSONObject: dados),
let jsonString = String(data: jsonData, encoding: .utf8) {
// Enviar de volta para WinDev via callback
NotificationCenter.default.post(name: .locationUpdated, object: jsonString)
}
}
}
```

## 3. Uso de Delegates e Callbacks

```windev
// Procedimento WinDev para receber callbacks
PROCÉDURE ReceberCallback(sResultado string)
Info("Resultado recebido: " + sResultado)
```

```swift
// Extensão para NotificationCenter
extension Notification.Name {
static let locationUpdated = Notification.Name("locationUpdated")
static let cameraResult = Notification.Name("cameraResult")
}

@objc public class CallbackManager: NSObject {

@objc public static func configurarObservadores() {
NotificationCenter.default.addObserver(
forName: .locationUpdated,
object: nil,
queue: .main
) { notification in
if let resultado = notification.object as? String {
// Chamar procedimento WinDev
self.chamarWinDev("ReceberCallback", com: resultado)
}
}
}

private static func chamarWinDev(_ procedimento: String, com parametro: String) {
// Implementação específica para chamar WinDev
// Usar bridge nativo do WinDev Mobile
}
}
```

## 4. Integração com APIs iOS Específicas

```swift
// Biometria e Touch ID / Face ID
@objc public class BiometriaManager: NSObject {

@objc public static func verificarBiometriaDisponivel() -> String {
let context = LAContext()
var error: NSError?

if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
switch context.biometryType {
case .faceID:
return "faceid_disponivel"
case .touchID:
return "touchid_disponivel"
default:
return "biometria_nao_disponivel"
}
}
return "erro_verificacao"
}

@objc public static func autenticarBiometria(_ mensagem: String) {
let context = LAContext()

context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: mensagem
) { success, error in
DispatchQueue.main.async {
let resultado = success ? "sucesso" : "falha"
NotificationCenter.default.post(
name: .biometriaResult,
object: resultado
)
}
}
}
}

// Keychain para armazenamento seguro
@objc public class KeychainManager: NSObject {

@objc public static func salvarDados(_ chave: String, _ valor: String) -> Bool {
let dados = valor.data(using: .utf8)!

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: chave,
kSecValueData as String: dados
]

SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
return status == errSecSuccess
}

@objc public static func lerDados(_ chave: String) -> String {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: chave,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]

var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)

if status == errSecSuccess,
let data = result as? Data,
let string = String(data: data, encoding: .utf8) {
return string
}
return ""
}
}
```

## 5. Configuração no Projeto WinDev Mobile

```windev
// Inicialização no projeto
PROCÉDURE InicializarSwift()

// Configurar observadores Swift
iOSAppelFonctionSwift("CallbackManager.configurarObservadores")

// Verificar recursos disponíveis
sBiometria est string = iOSAppelFonctionSwift("BiometriaManager.verificarBiometriaDisponivel")
Info("Biometria disponível: " + sBiometria)

// Procedimento para usar câmera
PROCÉDURE UsarCamera()
sResultado est string = iOSAppelFonctionSwift("CameraManager.abrirCamera")

// Procedimento para salvar dados seguros
PROCÉDURE SalvarDadosseguros(sChave string, sValor string)
bSucesso est boolean = iOSAppelFonctionSwift("KeychainManager.salvarDados", sChave, sValor)
SI PAS bSucesso ENTÃO
Erreur("Falha ao salvar dados no Keychain")
FIM
```

## 6. Considerações Importantes

### Configuração do Bridging Header

```objective-c
// WinDev-Bridging-Header.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreLocation/CoreLocation.h>
#import <LocalAuthentication/LocalAuthentication.h>
```

### Info.plist Necessário

```xml
<key>NSCameraUsageDescription</key>
<string>App precisa acessar a câmera</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>App precisa acessar localização</string>
<key>NSFaceIDUsageDescription</key>
<string>App usa Face ID para autenticação</string>
```

## 7. Debugging e Tratamento de Erros

```swift
@objc public class DebugManager: NSObject {

@objc public static func logDebug(_ mensagem: String) {
#if DEBUG
print("WinDev Swift Debug: \(mensagem)")
#endif
}

@objc public static func tratarErro(_ erro: String) -> String {
let errorInfo = [
"timestamp": Date().timeIntervalSince1970,
"erro": erro,
"plataforma": "iOS"
]

do {
let jsonData = try JSONSerialization.data(withJSONObject: errorInfo)
return String(data: jsonData, encoding: .utf8) ?? "{}"
} catch {
return "{\"erro_critico\": true}"
}
}
}
```

Essas técnicas permitem aproveitar todo o poder do iOS nativo dentro do Windev Mobile, mantendo a simplicidade do desenvolvimento WX enquanto acessa recursos avançados da plataforma.​​​​​​​​​​​​​​​​

Essas informações não estão no Help, mas pessoas que já programaram só com o Xcode sabem dessas camadas e aqui estou deixando explícito e também no https://forum.pcsoft.fr

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/